Skip to content
⚠️ This article was written in 2019. Some content may be outdated.

React Refs Forwarding and Use Cases

I recently used React ref forwarding in a project and found it more complex than expected. Here is a summary of the experience gained in practice.

Core Principle

useRef returns a mutable object with a current property that persists for the lifetime of the component. Unlike state, updating current does not trigger a re-render.

javascript
import React, { useRef, useEffect } from "react";

function TextInput() {
  const inputRef = useRef(null);

  useEffect(() => {
    inputRef.current.focus();
  }, []);

  return <input ref={inputRef} type="text" />;
}

Ref Forwarding with forwardRef

When you need to pass a ref through a component to a DOM node inside it:

javascript
const FancyInput = React.forwardRef((props, ref) => (
  <input ref={ref} className="fancy-input" {...props} />
));

// Parent component
function Parent() {
  const inputRef = useRef(null);

  const handleClick = () => {
    inputRef.current.focus();
  };

  return (
    <>
      <FancyInput ref={inputRef} placeholder="Click the button to focus" />
      <button onClick={handleClick}>Focus</button>
    </>
  );
}

useImperativeHandle: Exposing a Custom API

When the parent component should only have access to specific methods:

javascript
const CustomInput = React.forwardRef((props, ref) => {
  const inputRef = useRef(null);

  useImperativeHandle(ref, () => ({
    focus: () => inputRef.current.focus(),
    clear: () => {
      inputRef.current.value = "";
    },
    getValue: () => inputRef.current.value,
    // Only expose specific methods, not the entire DOM node
  }));

  return <input ref={inputRef} {...props} />;
});

// Parent can only call focus, clear, getValue
function Parent() {
  const inputRef = useRef(null);
  return (
    <>
      <CustomInput ref={inputRef} />
      <button onClick={() => inputRef.current.clear()}>Clear</button>
    </>
  );
}

Ref forwarding is mainly used for: focusing inputs in form libraries, integrating third-party imperative APIs, and building reusable component libraries that expose DOM methods.

MIT Licensed