10

I'm confused on the point of React.forwardRef. As explained in its documentation, I understand that its main use is for a Parent Component to gain access to DOM elements of the Child Component. But I can already do that without even having to use it.

Here is a code example that you can plug into CodeSandbox and see that it works:

import React, {useRef, useEffect} from "react";
import "./styles.css";

const ChildComponent = (props) => {

  useEffect( ()=> {
    props.callbackFunction()
  })

  return(
    <div ref={props.fRef}>
      {"hello"}
    </div>
  )
}


export default function App() {
  const callbackFunction = () => {
    console.log("The parent is now holding the forwarded ref to the child div: ")
    console.log(forwardedRef)
  }

  const forwardedRef = useRef(null)

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <ChildComponent name="gravy" callbackFunction={callbackFunction} fRef={forwardedRef}/>
    </div>
  );
}

Or here's the embed of this example. Honestly, I'm kind of new to this and I don't know exactly how embeds work and whether someone fiddling with the embed changes my original Sandbox or not, so I was hesitant to put it. But here it is. Example Forwarding Ref

In the example, the parent App() component successfully passes a ref to the child which the child attaches to its rendered div. After it renders, it calls a callback function to the parent. The parent then does a console log where it proves that its forwarded ref now has a hold of the child's div. And this is all done without React.forwardRef.

So what then is the use for React.forwardRef?

Wasit Shafi
  • 854
  • 1
  • 9
  • 15
Jordy
  • 415
  • 5
  • 13

2 Answers2

11

You're absolutely right that you can do what you've described. The downside is that you're forced to expose an API (ie: the fRef prop) for it to work. Not a huge deal if you're a solo developer building an app, but it can be more problematic eg. if you're maintaining an open-source library with a public API.

In that case, consumers of the library won't have access to the internals of a component, meaning you'd have to expose it for them somehow. You could simply do what you're suggesting in your example and add a named prop. In fact, that's what libraries did before React 16.3. Not a huge deal, but you'd have to document it so people know how to use it. Ideally, you'd also want some kind of standard that everyone used so it wasn't confusing (many libraries used the innerRef naming convention), but there'd have to be some consensus around that. So all doable, but perhaps not the ideal solution.

Using forwardRef, passing a ref to a component just works as expected. The ref prop is already standardized in React, so you don't need to go look at docs to figure out how to pass the ref down or how it works. However, the approach you describe is totally fine and if it meets your needs, by all means go with that.

ericgio
  • 3,094
  • 4
  • 25
  • 44
  • I have one more question. If a component is made with React.forwardRef, then how would you get a ref to that actual component instead of its inner rendered elements? Because when you attach a ref to the actual component, it will assumedly forward it to the rendered element in its child since its assumedly set up for that purpose. So it feels like a heavy tradeoff to no longer be able to have a ref simply to that component. Am I misunderstanding this? – Jordy Apr 01 '20 at 00:36
  • 2
    `forwardRef` is prob most useful with simple components that wrap HTML elements. If you have a complex component where you need to expose more than one thing, then you might use named props in that case in addition to (or instead of) a normal ref. For example a typeahead component composed of an input and menu might expose `inputRef` + `menuRef` (+ `ref` to access the component itself). You could also provide methods on the component to access the underlying elements (`ref.current.getInputNode()` + `ref.current.getMenuNode()`). – ericgio Apr 01 '20 at 05:49
1

As mentioned in the docs , it's useful for highly reusable components, meaning components that tend to be used like regular HTML DOM elements.

This is useful for component libraries where you have lots of "leaf" components. You've probably used one like Material UI.

Example:

Let's say you're maintaining a component library.

You create a <Button/> and <Input/> component that maybe just adds some default styling.

Notice how these components literally are just like regular HTML DOM elements with extra steps.

If these components were made to be used like regular HTML DOM elements, then I expect all the props to be the same, including ref, no?

Wouldn't it be tedious if to get the button ref from your <Button/> component I'd have to get it through something like fRef or buttonRef ?

Same with your <Input/>, do I have to go to the documentation just to find out what ref to use and it's something like inputRef ? Now I have to memorize?

Getting the ref should be as simple as <Button ref={}/>

Problem

As you might know, ref will not get passed through props because, like key, it is handled differently by React.

Solution

React.forwardRef() solves this so I can use <Button ref={}/> or <Input ref={}/>.

Community
  • 1
  • 1
Abe Caymo
  • 193
  • 7