preface

Ref forwarding is a technique that automatically passes a Ref from parent to child through the forwardRef API. This technique is not common and is used in the following scenarios:

  • forwardingrefInside the componentDOMnodes
  • Forwarding in higher-order componentsref

The chestnuts

Let’s start by writing a FancyButton component.

const FancyButton = (props) => {
    return (
         <input style={{width: 210}} type="text"/>
         <button>{props.children}</button>
    );
}
Copy the code

Render FancyButton in the parent App.

import * as React from 'react'; import * as ReactDOM from 'react-dom'; Const App = () => {return (<div> <FancyButton> <button> get focus </button> </div>); } ReactDOM.render(<App />, root);Copy the code

Now we want to focus the input in the FancyButton component by clicking “Get Focus”. You might think of manipulating the child’s DOM node in the parent component by passing the REF attribute from the parent component to the FancyButton component via props and binding the INPUT. Unfortunately, regular functions and class components do not accept ref arguments, and ref does not exist in props.

The forwardRef comes out.

React.forwardRef

ForwardRef (render) returns the React component and receives a render function with render(props, ref) as its signature. The second argument forwards the ref property it receives to the component that Render returns.

const FancyButton = React.forwardRef((props, ref) => {
    return (
       <div>
           <input ref={ref} style={{width: 210}} type="text"/>
           <button>{props.children}</button></button>
       </div>
    );
});
Copy the code

In this way, components using FancyButton can get the ref for the input of the underlying DOM node and access it if necessary. The complete code is as follows:

import * as React from 'react'; import * as ReactDOM from 'react-dom'; import {useRef} from 'react'; // const FancyButton = React. Callback ((props, ref) => {return (<div> <input ref={ref} style={{width: 1); 210}} type="text"/> <button>{props.children}</button></button> </div> ) }) const App = () => { const ref = useRef(); Const handleClick = () => {ref.current? .focus(); } return (<div> <FancyButton ref={ref}> </FancyButton> <button onClick={handleClick}>); } ReactDOM.render(<App />, root);Copy the code

Yet!!! React.forwardRef is usually used with useImperativeHandle.

useImperativeHandle

UseImperativeHandle lets you customize the instance values exposed to the parent component when using ref. In most cases, imperative code like ref should be avoided. UseImperativeHandle should be used together with the forwardRef.

useImperativeHandle(ref, createHandle, [deps])
Copy the code
  • Ref: Defines the ref of the current object
  • CreateHandle: a function that returns an object, the current of this ref
  • [DEPS] : dependency list. UseImperativeHandle reprints the instance properties of the child component to the parent when the listening dependency changes
import * as React from 'react'; import * as ReactDOM from 'react-dom'; import {useRef, useImperativeHandle} from 'react'; const FancyInput = React.forwardRef((props, ref) => { const inputRef = useRef(); useImperativeHandle(ref, () => ({ focus: () => { inputRef.current? .focus(); }})); return <input ref={inputRef} type="text"/> }); const App = () => { const fancyInputRef = useRef(); return ( <div> <FancyInput ref={fancyInputRef}/> <button onClick={() => fancyInputRef.current? </button> </div>)} reactdom.render (<App />, root);Copy the code

React.forwardRef (ref = ref; forwardRef); forwardRef (ref = ref; forwardRef); The official recommendation is not to use such a ref pass through.

UseImperativeHandle allows parent and child components to have their own refs, pass in the parent’s ref through the react. forwardRef, and customize the current open to parent components using useImperativeHandle.

Your thumbs-up is a great encouragement to me! Thanks for reading ~