React (Ref

Refs forwarding, Refs & DOM, and Hooks UseRef() and useImperativeHandle() are described in detail in the React documentation.

Because these chapters are scattered, they may be expensive to read for those who want to systematically study Ref. Together with the coherence of these knowledge, comparison can deepen the understanding of it.

Next, I will organize the context of the article according to my own understanding. Interested partners can read it in order directly, and I believe that they will have a new understanding of Ref in the end.

Let’s take a look at the context in which ref appears.

background

In a typical React data flow (top-down), if you want to change the child component in the parent component, you must change the state of the parent component to change the props received by the child component, triggering the child to rerender.

But there are special cases where we want to change the child component directly in the parent component. The child component to be modified can be a React component or directly a DOM element. In the following example, I want to autofocus the input field on the first rendering of the page:

// Modify the DOM element
class Parent extends React.Component {
    render() {
        return <input />; }}Copy the code
// Modify child components
class Child extends React.Component {
    render() {
        return <input />; }}class Parent extends React.Component {
    render() {
        return <Child />; }}Copy the code

Obviously, we need to take the input element and implement its focus() method.

Ref is a remedy for this situation.

To use ref, first we need to create it. In React, there are three ways to create a ref: React.createref (), callback ref, and Hook API: useRef(). Let’s look at the first one.

React.createRef()

function Parent(props) {
    const myRef = React.createRef();
    return <input ref={myref} />;
}
Copy the code

Create a ref with React. CreateRef (). Append to the React element via the ref attribute.

React passes a DOM element to the current property when the component is mounted and a NULL value when the component is unmounted. The ref is updated before the componentDidMount or componentDidUpdate lifecycle hook is triggered.

Now throughmyRef.currentYou can getinputThe element

Current is an attribute of ref whose value varies depending on the type of node:

  1. whenrefProperty is used toHTMLElement, whose value is this element.
  2. whenrefAttribute is used for customclassComponent, the value is the component instance.

Ok, let’s implement the focus input box mentioned above

// Modify the DOM element
class Parent extends React.Component {
    myRef = React.createRef();
    componentDidMount() {
        this.myRef.current.focus();
    }
    render() {
        return <input ref={this.myRef} />; }}Copy the code
// Modify child components
class Child extends React.Component {
    myRef = React.createRef();
    focusInput() {
        this.myRef.current.focus();
    }
    render() {
        return <input ref={this.myRef} />; }}class Parent extends React.Component {
    myRef = React.createRef();
    componentDidMount() {
        this.myRef.current.focusInput();
    }
    render() {
        return <Child ref={this.myRef} />; }}Copy the code

Note that the ref attribute cannot be applied to a function component because it has no instance.

// This code will not work and will report an error
function Child(props) {
    const myRef = React.createRef();
    const focusInput = () = > {
        myRef.current.focus();
    };
    return (
        <div>
            <input ref={myRef} />
            <input onClick={focusInput} />
        </div>
    );
}
class Parent extends React.Component {
    myRef = React.createRef();
    componentDidMount() {
        / / an error
        this.myRef.focusInput();
    }
    render() {
        return (
            // Child is not a class component, so ref does not take effect
            <Child ref={this.myRef} />); }}Copy the code

But there are workarounds, and there will be. Let’s move on to the second method of callback ref👀 ~

The callback ref

The ref callback takes the form of a function. This allows functions to take React component instances or HTML DOM as arguments. So like react.createref (), it also works with class components and the DOM.

Let’s change the above example to use a callback to ref.

// Modify the DOM element
class Parent extends React.Component {
    myRef = null;
    setInputRef = (element) = > {
        this.myRef = element;
    };
    componentDidMount() {
        // Note that myRef is the DOM object, no more myref.current
        this.myRef && this.myRef.focus();
    }
    render() {
        return <input ref={this.setInputRef} />; }}Copy the code
// Modify child components
class Child extends React.Component {
    myRef = null;
    setInputRef = (element) = > {
        this.myRef = element;
    };
    focusInput() {
        this.myRef.focus();
    }
    render() {
        return <input ref={this.setInputRef} />; }}class Parent extends React.Component {
    myRef = null;
    setInputRef = (component) = > {
        this.myRef = component;
    };
    componentDidMount() {
        this.myRef && this.myRef.focusInput();
    }
    render() {
        return <Child ref={this.setInputRef} />; }}Copy the code

In the example of modifying Child components, we call Child’s method in Parent to implement the function. This is because we get the child component instance through ref. However, the ref callback can directly retrieve the DOM node in the child component.

// Modify child components
function Child(props) {
    return <input ref={props.inputRef} />;
}
class Parent extends React.Component {
    myRef = null;
    setInputRef = (element) = > {
        this.myRef = element;
    };
    componentDidMount() {
        this.myRef && this.myRef.focusInput();
    }
    render() {
        return <Child inputRef={this.setInputRef} />; }}Copy the code

In the example above, the function is passed as props to the child component. Now this.myRef will be the input element directly.

In that case, consider the following code:

// Modify child components
function Child(props) {
    return <input ref={props.inputRef} />;
}
class Parent extends React.Component {
    myRef = React.createRef();
    componentDidMount() {
        this.myRef.current.focusInput();
    }
    render() {
        return <Child inputRef={this.myRef} />; }}Copy the code

Obviously, an error will be reported

How can we use React. CreateRef () to get the DOM element of the child component directly from the parent component instead of the component instance?

This brings us to the mystery of the previous sale. As mentioned earlier, there are methods for applying a REF to a function component. The same method is used to retrieve DOM elements from child components. The method is react.forwardref ().

React.forwardRef()

Forward, as the name implies, forwards the ref we created to any location in the child component. Let’s see how it’s used.

// Child
const Child = React.forwardRef((props, ref) = > <input ref={ref} />);

export default Child;
Copy the code
// Parent
class Parent extends React.Component {
    myRef = React.createRef();
    render() {
        return <Child ref={this.myRef} />; }}Copy the code

The ref for Child is the ref we created. The ref is passed to the input as the second parameter of the react. forwardRef function argument as the value of its ref property. That’s what it does through transmission.

There are two ways to create a REF and a way to get the DOM element of a child component directly. One final method for creating a ref belongs to the React Hook API: useRef().

useRef()

UseRef and React. CreateRef are much the same. Both are used to create ref objects.

function test(props) {
    const myRef = useRef(null);
    useEffect(() = >{ myRef.current.focus(); } []);return <input ref={myRef} />;
}
Copy the code

The power of useRef, however, is that it can easily save any value. Because it’s essentially a normal JS object. And useRef returns the same object no matter how the component is rerendered.

Let’s see how it works.

function Test(props) {
    const ref = useRef(null);
    useEffect(() = > {
        const id = setInterval(() = > {});
        ref.current = id;
        return () = > {
            clearInterval(ref.current);
        };
    });
    const clear = () = > {
        clearInterval(ref.current);
    };
    return (
        <div>
            <button onClick={clear}>clear</button>
        </div>
    );
}
Copy the code

React Ref. There are some less commonly used ones that are not introduced. I have placed the links below in logical order. Those of you who want to systematically follow the website again can follow this order.

1. React.createref

This chapter explains the context in which ref appears and why it is needed. How to create and use them in DOM and class components.

2. React.forwardRef

This section focuses on the use of React. CreateRef (). How to use it to bind the ref we created to any DOM element of any child component we want.

3. Ref in Hook

This section mainly introduces the usage of useRef and useImperativeHandle.

That’s all. I hope it will help you. Thank you for reading