Analysis of useRef
useRef returns a ref object, and the returned ref object remains unchanged throughout the entire life of the component.。
The most commonly used ref is two ways to use it:
Usage 1: Used to obtain the DOM (or component, but it needs to be a class component) element and operate the DOM;
import React, { memo, useRef } from 'react' const App = memo(() => { const inputRef = useRef() function inputDom() { () } return ( <div> <input type="text" ref={inputRef}/> <button onClick={inputDom}>Get focus</button> </div> ) }) export default App
Usage 2: Save a data, and this object can be saved and unchanged throughout the entire life cycle;
For example, when we modify the counter, the App component will be re-rendered, and the info object will also open up a new memory space in the heap memory; it means that every time we modify the counter, we get a new info object
import React, { memo, useState, useRef } from 'react' const App = memo(() => { const [counter, setCounter] = useState(10) function increment() { setCounter(counter + 1) } // Define an object const info = {} return ( <div> <h2>Current count: {counter}</h2> <button onClick={increment}>+1</button> </div> ) }) export default App
We can use useRef, because no matter how many times the useRef is rendered, the return is the same ref object.
import React, { memo, useState, useRef } from 'react' const App = memo(() => { const [counter, setCounter] = useState(10) function increment() { setCounter(counter + 1) } // Define an object const infoRef = useRef() return ( <div> <h2>{}-{}</h2> <h2>Current count: {counter}</h2> <button onClick={increment}>+1</button> </div> ) }) export default App
UseRef and useCallback can be solvedClosure Trap
The problem, there are corresponding cases in the previous article
useImperativeHandle
useImperativeHandle is not very easy to understand, it is a bit abstract, let's learn it bit by bit。
Let's first review the combination of ref and forwardRef:
Ref can be forwarded to child components through forwardRef;
The child component takes the ref created in the parent component and binds it to a certain element of its own;
The element bound to the ref in the child component can be obtained from the parent component.
import React, { memo, useRef,forwardRef } from 'react' const HelloWorld = memo(forwardRef((props, ref) => { return ( <input type="text" ref={ref} /> ) })) const App = memo(() => { const inputRef = useRef() function getInputDom() { // Get the input element in the child component () // Operate DOM () } return ( <div> <HelloWorld ref={inputRef}/> <button onClick={getInputDom}>SubcomponentsinputGet focus</button> </div> ) }) export default App
There is no problem with forwardRef's approach itself, but we directly expose the DOM of the child component to the parent component:
The problems directly exposed to the parent component are uncontrollable in some situations;
The parent component can perform any operations after getting the DOM;
However, in fact, in the above case, we just want the parent component to operate the focus, and others don't want it to operate at will
For example, the operation of modifying the content of an element
= "aaa"
Wait, we hope to limit its operation;
UseImperativeHandle to expose fixed operations (restrict operations):
useImperativeHandle requires two parameters to be passed:
- Parameter 1: Pass in a ref
- Parameter 2: Pass in a callback function, requiring the callback function to return an object, the object will be bound to the current property of the passed ref
Through the useImperativeHandle's Hook, the object returned by the second parameter of useImperativeHandle is bound together; so in the parent component, when using , the object returned by parameter two is actually used;
For example, in the following code, a method focus is exposed in the child component through useImperativeHandle
const HelloWorld = memo(forwardRef((props, ref) => { // Process the ref passed in the parent component in the child component through useImperativeHandle useImperativeHandle(ref, () => { return { focus() { ("focus call") } } }) return ( <input type="text" ref={ref} /> ) }))
Then in the App parent component, it is essentially the object returned by parameter two.
const App = memo(() => { const inputRef = useRef() function getInputDom() { // The object obtained is also the return value of parameter two () // In essence, the focus method in the object returned by parameter two is called () } return ( <div> <HelloWorld ref={inputRef}/> <button onClick={getInputDom}>SubcomponentsinputGet focus</button> </div> ) })
But we don't want to print a sentence as simply as in the above code, but want to really get the focus
Then we can redefine a ref object inside the child component, and then expose the operation we want to expose.
For example, in the following code, we only expose the operation of obtaining focus, which will become safer and more controllable; what function we want to use externally is entirely determined by the internal subcomponents
import React, { memo, useRef,forwardRef, useImperativeHandle } from 'react' const HelloWorld = memo(forwardRef((props, ref) => { // Redefine a ref object inside the child component const inputRef = useRef() // Process the ref passed in the parent component in the child component through useImperativeHandle useImperativeHandle(ref, () => { return { focus() { () } } }) return ( // Bind the ref object defined inside the component to the form <input type="text" ref={inputRef} /> ) })) const App = memo(() => { const inputRef = useRef() function getInputDom() { () // In essence, the object returned by parameter two is called () } return ( <div> <HelloWorld ref={inputRef}/> <button onClick={getInputDom}>SubcomponentsinputGet focus</button> </div> ) }) export default App
This is the article about how React Hooks - useRef and useImperativeHandle is introduced here. For more information about React useRef and useImperativeHandle, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!