14
头图

I guess you are all familiar with these HOOKS: useState , useEffect , useContext , useMemo . But when I saw useImperativeHandle first time, I looked confused (what the hell is this~~~).

1. What is it?

useImperativeHandle on React's official website is also relatively brief. The summary is: sub-components useImperativeHandle to allow the parent component to output arbitrary data .

// FancyInput组件作为子组件
const FancyInput = React.forwardRef(function FancyInput(props, ref) {
  const inputRef = useRef();

  // 命令式的给`ref.current`赋值个对象
  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus()
    }
  }));
  
  return <input ref={inputRef} ... />
})

// Example组件作为父组件
function Example() {
  const fancyInputRef = useRef()

  const focus = () => {
    fancyInputRef.current.focus()
  }

  return (
    <>
      <FancyInput ref={fancyInputRef} />
    </>
  )
}

2. How to use it?

2.1 Syntax

useImperativeHandle(ref, createHandle, [deps])
  1. ref
    ref object that needs to be assigned.
  2. createHandle
    createHandle return value as a function of ref.current value.
  3. [deps]
    The dependency array, if the dependency changes, the createHandle function will be executed again.

2.2 Advanced: When will the createHandle function be executed?

The test found that useLayoutEffect executed at the same timing as 061545553d8903.
Modify the content of the FancyInput

const FancyInput = React.forwardRef(function FancyInput(props, ref) {
    const inputRef = useRef();
    console.log('render 1')

    useLayoutEffect(() => {        
        console.log('useEffect1', ref)
    })

    useImperativeHandle(ref, function() {        
        debugger
        console.log('useImperativeHandle')
        return {
            focus: () => {
                inputRef.current.focus();
            }
        }
    })    

    useLayoutEffect(() => {        
        console.log('useEffect2', ref);
    })

    console.log('render 2')
    return <input ref={inputRef}  placeholder="FancyInput"/>;
})

image.png
Take a look at the console output found createHandle perform timing functions and useLayoutEffect consistent, so ensures that in any position of useEffect can get the latest in ref.current value .

Note: execution createHandle function there is a precondition, namely useImperativeHandle first real reference ref must have a value (otherwise perform createHandle function no meaning ah).

2.3 Application scenarios

At present, the project has many usage scenarios, mainly to solve the problem of obtaining the data of the child component by the parent component or calling the function declared in the child component.
For example, a use of formik library

React.useImperativeHandle(innerRef, () => formikbag);

2.4 Best practices

Several usage suggestions are given on the React official website:

  1. Try to avoid ref.current assigning 061545553d8afc, and try to use declarative (that is, let React handle it internally);
  2. forwardRef with 061545553d8b3d
    This is not necessarily true. For example, the fomik library above does not do so.

Three, principle

Let’s review how we used ref before:

  1. ref access instances of subcomponents or DOM elements at the beginning of the period;
  2. Later useRef appeared, we can use useRef in the function component to store some data similar to member variables.

's review how React handles declarative ref 161545553d8c1d:

React will assign the current property with the DOM element when the component mounts, and assign it back to null when it unmounts.

Through previous knowledge, we can reach a few consensus:

  1. To ref.current assignment is a side effect, it is generally in Did to the function or event handler in ref.current assignment;
  2. The value of ref.current should be cleaned up when the component is uninstalled.

In essence, useImperativeHandle is helping us do these things.

Four, why do you need useImperativeHandle

We all know that the parent component can use ref to access the child component instance or DOM element, which is actually equivalent to the child component outputting its own instance or DOM element to the parent component. Using useImperativeHandle child component can output any data to the parent component.

Organized from GitHub notes: useImperativeHandle


普拉斯强
2.7k 声望53 粉丝

Coder