Learn react recently. Record the process of learning react.

Hook is a new feature in React 16.8. It lets you use state and other React features without having to write a class. UseRef is one of the commonly used hooks.

The most basic use of useRef is to manipulate the DOM in function components. The corresponding API in the class component is createRef. Let’s take a look at the basic uses of the two apis, the differences between them, and the benefits of useRef.


1. DOM related operations

We use createRef and useRef to do the same thing in a class component and a function component, respectively: the parent component gets the state and methods of the child component

1, createRef

// Class ParentComponent extends React.Component {constructor(props) {super(props); this.myRef = React.createRef(null); } render() { return ( <div> <ChildComponent ref={this.myRef}></ChildComponent> <button onClick={() => { alert(this.myRef.current.state.childName); }} > get child childName from parent </button> <button onClick={() => { this.myRef.current.sayHello(); }} > get child function from parent </button> </div> ); }} // Class ChildComponent extends react.component.constructor (props) {super(props); this.state = { childName: "mongo", }; } sayHello() { alert("hello! " + this.state.childName); } render() { return ( <div> <button onClick={() => { this.sayHello(); }} > alert function by child </button> </div> ); }}Copy the code

2, useRef

const ParentComponentByUseRef = () => { const myRef = useRef(); return ( <div> <ChildComponentByUseRef ref={myRef}></ChildComponentByUseRef> <button onClick={() => { alert(myRef.current.childName); }} > get childName by parent </button> <button onClick={() => { myRef.current.sayHello(); }} > get function by parent </button> </div> ); }; Const ChildComponentByUseRef = forwardRef((props, ref) => {useImperativeHandle(ref, props) => () => ({ sayHello, childName, ref })); const [childName, setChildName] = useState("mongo"); const sayHello = () => { alert("hello! " + childName); }; return ( <div ref={ref}> <button onClick={() => { sayHello(); }} > get function by child </button> <button onClick={() => { setChildName("mongowoo"); }} > change childName </button> </div> ); }); export default forwardRef(ParentComponentByUseRef);Copy the code

Use fowardRef and useImperativeHandle to forward refs

FowardRef: React. ForwardRef creates a React component that forwards the ref properties it receives to another component in its component tree. This technique is uncommon, but is particularly useful in two scenarios:

  • Forward refs to the DOM component
  • Forwarding refs in higher-order components

UseImperativeHandle: useImperativeHandle allows you to customize the instance value exposed to the parent component when using a ref. In most cases, imperative code like ref should be avoided. UseImperativeHandle should be used together with the forwardRef


The difference between createRef and useRef

We know that useRef is a new API from hooks, which cannot be used in class functions. Can createRef be used in function components? Let’s try it out. Write a simple button click to set the effect of Input Focus.

const createRefInFunction = () => {
    const myRef = createRef(null);
    return (
        <div>
            <input ref={myRef}></input>
            <button
                onClick={() => {
                    myRef.current.focus();
                }}
            >
                set focus
            </button>
        </div>
    );
};

export default createRefInFunction;
Copy the code

It turns out that createRef is also available in function components, so why add a useRef API?

Looking at the useRef definition, we can see that the official documentation already states how it differs from createRef:

UseRef returns a mutable ref object whose.current property is initialized as the passed parameter (initialValue). The ref object returned remains constant throughout the life of the component.

As you can see, createRef returns a new reference every time it renders, while useRef returns the same reference every time. It might be hard to understand from the text, but let’s write a simple demo.

const useRefAndCreateRefDiffrent = () => { const [renderIndex, setRenderIndex] = useState(1); const refFromUseRef = useRef(); const refFromCreateRef = createRef(); if (! refFromUseRef.current) { refFromUseRef.current = renderIndex; } if (! refFromCreateRef.current) { refFromCreateRef.current = renderIndex; } return ( <div> <p>current render index is: {renderIndex}</p> <p>refFromUseRef render index is: {refFromUseRef.current}</p> <p>refFromCreateRef render index is: {refFromCreateRef.current}</p> <button onClick={() => { setRenderIndex((prev) => prev + 1); }} > add render index </button> </div> };Copy the code

As you can see from the results, index has been increased to 7, createRef displays 7, and useRef displays only 1. As you can see, as render rerenders, createRef values are rerendered each time. UseRef initializes only once, which is why it finally displays 1.


3. UseRef’s magic

We learned that useRef can not only retrieve the forward DOM, but can also store any variable and has the feature of being initialized only once. You can use this feature for specific needs.

For example, get the last state value.

const getPreCount = () => {
    const [count, setCount] = useState(0);
    const preCount = useRef();

    useEffect(() => {
        preCount.current = count;
    });

    return (
        <div>
            {console.log("in render")}
            <div>precount:{preCount.current}</div>
            <p>you clicked {count} times</p>
            <button onClick={() => setCount(count + 1)}>Click Me</button>
        </div>
    );
};
Copy the code

The results are as follows:


End: I’m just learning React.