These docs are old and won’t be updated. Go toreact.dev for the new React docs.
These new documentation pages teach modern React and include live examples:
Ref forwarding is a technique for automatically passing aref through a component to one of its children. This is typically not necessary for most components in the application. However, it can be useful for some kinds of components, especially in reusable component libraries. The most common scenarios are described below.
Consider aFancyButton component that renders the nativebutton DOM element:
functionFancyButton(props){return(<buttonclassName="FancyButton">{props.children}</button>);}React components hide their implementation details, including their rendered output. Other components usingFancyButtonusually will not need toobtain a ref to the innerbutton DOM element. This is good because it prevents components from relying on each other’s DOM structure too much.
Although such encapsulation is desirable for application-level components likeFeedStory orComment, it can be inconvenient for highly reusable “leaf” components likeFancyButton orMyTextInput. These components tend to be used throughout the application in a similar manner as a regular DOMbutton andinput, and accessing their DOM nodes may be unavoidable for managing focus, selection, or animations.
Ref forwarding is an opt-in feature that lets some components take aref they receive, and pass it further down (in other words, “forward” it) to a child.
In the example below,FancyButton usesReact.forwardRef to obtain theref passed to it, and then forward it to the DOMbutton that it renders:
const FancyButton= React.forwardRef((props, ref)=>(<buttonref={ref}className="FancyButton">{props.children}</button>));// You can now get a ref directly to the DOM button:const ref= React.createRef();<FancyButtonref={ref}>Click me!</FancyButton>;This way, components usingFancyButton can get a ref to the underlyingbutton DOM node and access it if necessary—just like if they used a DOMbutton directly.
Here is a step-by-step explanation of what happens in the above example:
React.createRef and assign it to aref variable.ref down to<FancyButton ref={ref}> by specifying it as a JSX attribute.ref to the(props, ref) => ... function insideforwardRef as a second argument.ref argument down to<button ref={ref}> by specifying it as a JSX attribute.ref.current will point to the<button> DOM node.Note
The second
refargument only exists when you define a component withReact.forwardRefcall. Regular function or class components don’t receive therefargument, and ref is not available in props either.Ref forwarding is not limited to DOM components. You can forward refs to class component instances, too.
When you start usingforwardRef in a component library, you should treat it as a breaking change and release a new major version of your library. This is because your library likely has an observably different behavior (such as what refs get assigned to, and what types are exported), and this can break apps and other libraries that depend on the old behavior.
Conditionally applyingReact.forwardRef when it exists is also not recommended for the same reasons: it changes how your library behaves and can break your users’ apps when they upgrade React itself.
This technique can also be particularly useful withhigher-order components (also known as HOCs). Let’s start with an example HOC that logs component props to the console:
functionlogProps(WrappedComponent){classLogPropsextendsReact.Component{componentDidUpdate(prevProps){ console.log('old props:', prevProps); console.log('new props:',this.props);}render(){return<WrappedComponent{...this.props}/>;}}return LogProps;}The “logProps” HOC passes allprops through to the component it wraps, so the rendered output will be the same. For example, we can use this HOC to log all props that get passed to our “fancy button” component:
classFancyButtonextendsReact.Component{focus(){// ...}// ...}// Rather than exporting FancyButton, we export LogProps.// It will render a FancyButton though.exportdefaultlogProps(FancyButton);There is one caveat to the above example: refs will not get passed through. That’s becauseref is not a prop. Likekey, it’s handled differently by React. If you add a ref to a HOC, the ref will refer to the outermost container component, not the wrapped component.
This means that refs intended for ourFancyButton component will actually be attached to theLogProps component:
import FancyButtonfrom'./FancyButton';const ref= React.createRef();// The FancyButton component we imported is the LogProps HOC.// Even though the rendered output will be the same,// Our ref will point to LogProps instead of the inner FancyButton component!// This means we can't call e.g. ref.current.focus()<FancyButtonlabel="Click Me"handleClick={handleClick}ref={ref}/>;Fortunately, we can explicitly forward refs to the innerFancyButton component using theReact.forwardRef API.React.forwardRef accepts a render function that receivesprops andref parameters and returns a React node. For example:
functionlogProps(Component){classLogPropsextendsReact.Component{componentDidUpdate(prevProps){ console.log('old props:', prevProps); console.log('new props:',this.props);}render(){const{forwardedRef,...rest}=this.props;// Assign the custom prop "forwardedRef" as a refreturn<Componentref={forwardedRef}{...rest}/>;}}// Note the second param "ref" provided by React.forwardRef.// We can pass it along to LogProps as a regular prop, e.g. "forwardedRef"// And it can then be attached to the Component.return React.forwardRef((props, ref)=>{return<LogProps{...props}forwardedRef={ref}/>;});}React.forwardRef accepts a render function. React DevTools uses this function to determine what to display for the ref forwarding component.
For example, the following component will appear as ”ForwardRef” in the DevTools:
const WrappedComponent= React.forwardRef((props, ref)=>{return<LogProps{...props}forwardedRef={ref}/>;});If you name the render function, DevTools will also include its name (e.g. ”ForwardRef(myFunction)”):
const WrappedComponent= React.forwardRef(functionmyFunction(props, ref){return<LogProps{...props}forwardedRef={ref}/>;});You can even set the function’sdisplayName property to include the component you’re wrapping:
functionlogProps(Component){classLogPropsextendsReact.Component{// ...}functionforwardRef(props, ref){return<LogProps{...props}forwardedRef={ref}/>;}// Give this component a more helpful display name in DevTools.// e.g. "ForwardRef(logProps(MyComponent))"const name= Component.displayName|| Component.name; forwardRef.displayName=`logProps(${name})`;return React.forwardRef(forwardRef);}