157

I see that React.forwardRef seems to be the sanctioned way of passing a ref to a child functional component, from the react docs:

const FancyButton = React.forwardRef((props, ref) => (
  <button ref={ref} className="FancyButton">
    {props.children}
  </button>
));

// You can now get a ref directly to the DOM button:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;

However, what is the advantage of doing this over simply passing a custom prop?:

const FancyButton = ({ innerRef }) => (
  <button ref={innerRef} className="FancyButton">
    {props.children}
  </button>
));

const ref = React.createRef();
<FancyButton innerRef={ref}>Click me!</FancyButton>;

The only advantage I can think of is maybe having a consistent api for refs, but is there any other advantage? Does passing a custom prop affect diffing when it comes to rendering and cause additional renders, surely not as the ref is stored as mutable state in the current field?

Say for example you wanted to pass multiple refs (which tbh, might indicate code smell, but still), then the only solution I can see would be to use customRef props.

I guess my question is what is the value of using forwardRef over a custom prop?

zhulien
  • 5,145
  • 3
  • 22
  • 36
Lesbaa
  • 1,979
  • 2
  • 12
  • 15

2 Answers2

140

Even React docs mention the custom ref prop as a more flexible approach to forwardRef:

If you use React 16.2 or lower, or if you need more flexibility than provided by ref forwarding, you can use this alternative approach and explicitly pass a ref as a differently named prop.

There is also a gist, in which Dan Abramov writes about its advantages:

  • compatible with all React versions
  • works for class and function components
  • simplifies passing a ref to a nested component several layers deep

I would add, that passing refs as usual props does not cause breaking changes and is the way to go for multiple refs. The only advantages of forwardRef coming to my mind are:

  • uniform access API for DOM nodes, functional and class components (you mentioned that)
  • ref attribute does not bloat your props API, e.g. if you provide types with TypeScript

Does passing a custom prop affect diffing when it comes to rendering and cause additional renders?

A ref can potentially trigger a re-render if you pass an inline callback ref function down as prop. But it is a better idea anyway to define it as class instance method or via some memoization like useCallback.

ford04
  • 66,267
  • 20
  • 199
  • 171
  • 1
    Awesome thanks Ford, I kind of thought that might be the case was just keen to shine some light on it. – Lesbaa Feb 17 '20 at 10:40
  • 3
    the advantage points are't quite big enough reason to introduce an entire API, just code bloat imho – some_groceries Jun 13 '20 at 15:37
  • This is bonkers. Function Components ignore the `ref` prop (does not pass it as prop, and sets `current = null`. So, it seems forwardRef() has no justification except to encourage black boxing of components. – Uri Kutner Oct 06 '20 at 13:39
  • 1
    the major disadvantage of `React.forwardRef` is that you lose type checking with regards to the `Props` of a component. At least I haven't discovered how to use `forwardRef` and keep type checking for passed properties. – Marcus Junius Brutus Jun 01 '21 at 14:22
  • @MarcusJuniusBrutus Is this what you're looking for? `ForwardRefExoticComponent & RefAttributes>` – ChronicLogic Feb 07 '23 at 18:15
0

If you want a level of abstraction in ChildComponent, forwards Refs can be use in addition with useImperativeHandle hook only to expose specific methods of ref

eg:

 useImperativeHandle(ref, () => {
    return {
      focus() {
        inputRef.current.focus();
      },
      scrollIntoView() {
        inputRef.current.scrollIntoView();
      },
    };
  }, []);

here parent component can only access focus and scrollIntoView methods