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])
ref
ref
object that needs to be assigned.createHandle
:createHandle
return value as a function ofref.current
value.[deps]
The dependency array, if the dependency changes, thecreateHandle
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"/>;
})
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:
- Try to avoid
ref.current
assigning 061545553d8afc, and try to use declarative (that is, let React handle it internally); 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:
ref
access instances of subcomponents or DOM elements at the beginning of the period;- Later
useRef
appeared, we can useuseRef
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:
- To
ref.current
assignment is a side effect, it is generally inDid
to the function or event handler inref.current
assignment; - 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
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。