4

Let's say I have a component with a scrollable subcomponent, and I want to expose the ability to scroll:

const MyComponent = (props) => {
    return <ScrollView ... />
}

I want to be able to do

<MyComponent ref={myRef} />

...

myRef.scrollTo({x: 0});

So I need a way to forward the ref to the <ScrollView>. Let's try putting the ref on the props:

const MyComponent = (props) => {
    return <ScrollView ref={props.scrollRef} ... />
}

...

<MyComponent scrollRef={myRef} />

...

myRef.scrollTo({x: 0});

I just tried that with React Native on iOS, and it indeed works. I see several advantages over React.forwardRef:

  • Simpler, because I don't need to use another React API.
  • Works also if there is more than one child who needs ref forwarding.
  • Seems to me that this approach is

What's the advantage of React.forwardRef? Why was it added in React 16.3?

cheesus
  • 11,077
  • 10
  • 64
  • 122
  • 1
    Have you read the [docs](https://reactjs.org/docs/forwarding-refs.html)? – Bhojendra Rauniyar Jul 16 '20 at 09:08
  • Does this answer your question? [value of using React.forwardRef vs custom ref prop](https://stackoverflow.com/questions/58578570/value-of-using-react-forwardref-vs-custom-ref-prop) – Bhojendra Rauniyar Jul 16 '20 at 09:15
  • @BhojendraRauniyar 1) Yes, please show me the part of the docs that explains this. 2) Have you read the docs of StackOverflow, i.e. why it exists? Simply pointing to documentation does not answer a question. – cheesus Jul 16 '20 at 09:18
  • @BhojendraRauniyar this seems indeed a duplicate. However, in the other question, I just see two advantages of using `React.forwardRef`, and those advantages don't seem big. Would be glad to know why the React team added `forwardRef` in React 16.3 – cheesus Jul 16 '20 at 09:20
  • So your question is basically why its added? What kind of answer do you expect, did you check the merge commits in React 16.3 if you wonder "why in 16.3"? – Dennis Vash Jul 16 '20 at 09:27
  • @DennisVash my question is, why do we need it. The other question lists two advantages, but it seems strange to me that it was added to React just because of them. I was expecting something like "there is this one use case which you could not implement cleanly without `React.forwardRef`, so the team decided to add it to the framework". – cheesus Jul 16 '20 at 09:38
  • So basically you should ask about the use case because the advantages are a duplicate question. – Dennis Vash Jul 16 '20 at 09:45
  • @DennisVash Yeah I see. Thought the title would make it clear. – cheesus Jul 16 '20 at 11:39

1 Answers1

5

Note that there is no difference between using another named prop like innerRef FOR FORWARDING, it will work the same.


Refactoring class components

Since React moved toward function components (hooks) you might want to refactor the class component code to a function component without breaking the API.

// Refactor class component API to function component using forwardRef
<Component ref={myRef} />

React.forwardRef will be your only option (further explained in details).

Clean API

As a library author you may want a predictable API for ref forwarding.

For example, if you implemented a Component and someone wants to attach a ref to it, he has two options depending on your API:

<Component innerRef={myRef} />
  • The developer needs to be aware there is a custom prop for forwarding
  • To which element the innerRef attached? We can't know, should be mentioned in the API or we console.log(myRef.current)

<Component ref={myRef} />
  • Default behavior similar to ref prop used on HTML elements, commonly attached to the inner wrapper component.

Notice that React.forwardRef can be used for function component and HOC (for class component see alternative below).

Ref forwarding is not limited to DOM components. You can forward refs to class component instances, too.

For function components, forwardRef sometimes comes with useImperativeHandle combo (in class component you just call the class methods on ref instance: ref.current.myAttr().

// Same usage
<Component ref={myRef} />

const Component = React.forwardRef((props, ref) => {
  // you can forward ref <div ref={ref} />
  // you can add custom attributes to ref instance with `useImperativeHandle`
  // like having ref.myAttribute() in addition to ones attached to other component.
});

Important behavior of ref prop without forwardRef.

For the class component, this code alone will attach the ref to CLASS INSTANCE which is not useful by itself and need another ref for forwarding:

// usage, passing a ref instance myRef to class Component
<Component ref={myRef} />

Full example, check the logs:

// We want to forward ref to inner div
class ClassComponent extends React.Component {
  innerRef = React.createRef();
  render() {
    // Notice that you can't just `this.props.ref.current = node`
    // You don't have `ref` prop, it always `undefined`.
    return <div ref={this.innerRef}>Hello</div>;
  }
}

const Component = () => {
  const ref = React.useRef();

  useEffect(() => {
    // The ref attached to class instance
    console.log(ref.current);
    // Access inner div through another ref
    console.log(ref.current.innerRef);
  }, []);

  return <ClassComponent ref={ref} />;
};

Edit React Template (forked)

In function components, it won't even work because functions don't have instances.

By default, you may not use the ref attribute on function components because they don’t have instances. [1]

Dennis Vash
  • 31,365
  • 5
  • 46
  • 76
  • Do refs generally not work with function components? Or just ref forwarding? – cheesus Jul 16 '20 at 11:39
  • Refs as **using the property ref** `ref={ref}` don't work with function components :-) You have to use `React.forwardRef` on them. – Dennis Vash Jul 16 '20 at 11:40
  • But isn't it a different concept? Why inventing "ref forwarding" when it's all about refs with function components? I mean, in your example, `` does not do any ref forwarding to its child components, right? – cheesus Jul 16 '20 at 11:41
  • Well, you don't know what it does, that's the all point - not to break existing code. I'll add another example maybe it will clarify – Dennis Vash Jul 16 '20 at 11:43
  • Starts to get clearer, thanks :-) However, instead of implementing ref forwarding, they could have just added `ref` as a second parameter in function components, right? This would not have broken any existing code, since there was no second parameter before that. But since they saw other advantages in ref forwarding, they did it that way. – cheesus Jul 16 '20 at 13:42
  • Yes they could. – Dennis Vash Jul 16 '20 at 13:43
  • Could you explain why "you can't add ref instance to a function component" ? – Vencovsky Jan 27 '21 at 11:04
  • Make a custom function component and try passing a ref instance to it via ref prop like in class component – Dennis Vash Jan 27 '21 at 11:07
  • I know that that won't work, but I want to understand why? What is different in function components compared to class component that you can't pass a ref? I know this isn't what the questions is about, but I'm asking in the comments to avoid creating a new question. – Vencovsky Jan 27 '21 at 11:18
  • 1
    On contrary, you should ask a question instead of doing it in the comments. – Dennis Vash Jan 27 '21 at 11:19
  • 1
    @Vencovsky Ive updated the answer, there were some mistakes in it – Dennis Vash Jan 27 '21 at 12:46