How to deeply understand React's ref attribute

How to deeply understand React's ref attribute

Overview

First of all, Refs and ref are two concepts. Refs is an object provided by React that can be created using a specific API. The structure of this object is as follows:

This object has only one attribute, which is current. So what is this object used for?

Refs allow us to access DOM nodes or React elements created in the render method. (DOM nodes refer to native DOM elements, and the React elements created in the render() method refer to React class component elements)

We can imagine such a requirement, two brother elements, one is div and the other is button. Now I want to change the background color of the div by clicking the button. In native DOM technology, we can use document.querySelector('xxx') in the button click function to select the div node and then change its background style. However, whether in frameworks such as Vue or React, page elements are generated dynamically and cannot be obtained using the DOM API. Moreover, most of the elements operated in React are not native DOM elements, but React elements. So how do you select a native DOM element or React element?

In fact, in theory, we don’t need to perform any selection operations, as this will lose the concept of component independence in the front-end framework. Generally, events are handled through component communication. In the above situation, you can use EventBus to communicate with components. Trigger custom events in the button click event, listen to custom events in the div, and let the button notify the div to change the background color in the form of event notification, instead of directly obtaining the div for operation in the button event.

But React provides us with a way to directly access DOM elements and React elements, that is, through Refs. The way to use it is very simple, that is, add a ref attribute to the element you want to access, and attach the Refs object to the ref attribute. Then the current attribute of the Refs object is no longer empty, but the corresponding DOM element or React element instance.

1. Creation of Refs object

In React, there are two ways to create Ref objects:

1.1 React.createRef()

React.createRef() creates a Ref object, which can be accessed by attaching it to the ref attribute.
This method can be used in both function components and class components.

1.2 React.useRef(initialValue)

After adding Hook in React 16.8, there is another Hook that can create Ref objects. That is, React.useRef(initialValue).
useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned ref object remains unchanged throughout the lifecycle of the component.
This method can only be used in function components.

2. Use of the ref attribute

The ref attribute can only be added to native DOM elements or React class components. You cannot use the ref attribute on function components because function components do not have instances.

If you want to use the ref attribute on a function component, you can forward the Ref to the native DOM element inside the function component through React.forwardRef.

2.1 Add ref to native DOM elements

Inside a class component

class App extends React.Component {
    constructor(props){
        super(props)
        this.myRef = React.createRef()
    } 
    componentDidMount(){
        console.log(this.myRef)
        console.log(this.myRef.current)
    }
    render(){
        return (
            <div ref={this.myRef}>I am the App component</div>
        )
    }
}

Inside a function component

const App = ()=>{
    const myRef = React.useRef(null)
    //const myRef = React.createRef() Both ways of creating ref objects can be React.useEffect(()=>{
        console.log(myRef)
        console.log(myRef.current)
    },[]) //Simulation life cycle return (
        <div ref={myRef}>I am the div that uses ref inside the function component</div>
    )
}

2.2 Add ref to class component

class ClassChild extends React.Component{
    render(){
        return (
            <div>I am the class child component ClassChild of the App component</div>
        )
    }
}

class App extends React.Component {
    constructor(props){
        super(props)
        this.myRef = React.createRef()
    } 
    componentDidMount(){
        console.log(this.myRef)
        console.log(this.myRef.current)
    }
    render(){
        return (
            <ClassChild ref={this.myRef}/>
        )
    }
}

2.3 Add ref to the native DOM element forwarded by the class component

The principle of ref forwarding is to pass the ref object defined in the parent component to the child component as a normal attribute, and then the child component receives it through props and assigns it to its own DOM element.

class ClassChild extends React.Component{
    render(){
        return (
            <div ref={this.props.refProp}>I am the class child component ClassChild of the App component</div> //Added ref
        )
    }
}

class App extends React.Component {
    constructor(props){
        super(props)
        this.myRef = React.createRef()
    } 
    componentDidMount(){
        console.log(this.myRef)
        console.log(this.myRef.current)
    }
    render(){
        return (
            <ClassChild refProp={this.myRef}/> // passed as a normal property)
    }
}

2.4 Add ref to the native DOM element forwarded by the function component

According to the principle of class component forwarding, the implementation method I thought of is as follows:

const FunChild = (props)=>{
    return (
        <div ref={props.refProp}>I am a function component FunChild</div>
    )
}
class App extends React.Component {
    constructor(props){
        super(props)
        this.myRef = React.createRef()
    } 
    componentDidMount(){
        console.log(this.myRef)
        console.log(this.myRef.current)
    }
    render(){
        return (
            <FunChild refProp={this.myRef}/>
        )
    }
}

This implementation is possible, but it is not the way to use the ref attribute directly on the function component. React provides a way to use ref directly on the function component, which is to use React.forwardRef to create a React element.

React.forwardRef

const FunChild = React.forwardRef((props, ref)=>{
    return (
        <div ref={ref}>I am the function component FunChild</div>
    )
}) // Use React.forwardRef to transform the function component class App extends React.Component{
    constructor(props){
        super(props)
        this.myRef = React.createRef()
    } 
    componentDidMount(){
        console.log(this.myRef)
        console.log(this.myRef.current)
    }
    render(){
        return (
            <FunChild ref={this.myRef}/> // Pass ref directly to the function component
        )
    }
}

It feels like React.forwardRef just extracts the ref attribute from props alone.
Although the above method implements the use of ref attributes on function components, the Ref object at this time is the native DOM element or other class component inside the function component being accessed. In other words, the function component here only plays a forwarding role.

3. Callback Refs

In the above methods, we create a Ref object and mount it to a native DOM element or class component through the ref attribute to access the element or instance.
In fact, the ref attribute can receive a callback function in addition to a Ref object.
When the ref attribute receives a Ref object, its corresponding DOM element or class component instance is directly assigned to the current attribute in the Ref object. When the ref attribute receives a callback function, the callback function is called with its corresponding DOM element or class component instance as the parameter of the callback function.
Therefore, we can use callback Refs without relying on Ref objects and more flexibly control the elements or instances to be accessed.

class App extends React.Component {
    constructor(props){
        super(props)
        this.myRef = null
        this.setMyRef = (element)=>{
            this.myRef = element
        }
    } 
    componentDidMount(){
        console.log(this.myRef)
    }
    render(){
        return (
            <div ref={this.setMyRef}>I am the App component</div>
        )
    }
}

The above is the details of how to deeply understand React’s ref attribute. For more information about deeply understanding React’s ref attribute, please pay attention to other related articles on 123WORDPRESS.COM!

You may also be interested in:
  • In-depth understanding of the three core properties of React
  • Detailed explanation of the use of Refs in React's three major attributes
  • Detailed explanation of the use of props in React's three major attributes
  • Detailed explanation of the use of state in React's three major attributes
  • Do you know the three major properties of React?

<<:  Tomcat components illustrate the architectural evolution of a web server

>>:  Nginx proxy axios request and precautions

Recommend

Click the toggle button in Vue to enable the button and then disable it

The implementation method is divided into three s...

CSS transparent border background-clip magic

This article mainly introduces the wonderful use ...

How to remove the dividing line of a web page table

<br />How to remove the dividing lines of a ...

HTML Tutorial: Collection of commonly used HTML tags (4)

Related articles: Beginners learn some HTML tags ...

How to install and connect Navicat in MySQL 8.0.20 and what to pay attention to

Things to note 1. First, you need to create a my....

A brief analysis of JS original value and reference value issues

Primitive values ​​-> primitive types Number S...

How to deploy Redis 6.x cluster through Docker

System environment: Redis version: 6.0.8 Docker v...

A detailed analysis and processing of MySQL alarms

Recently, a service has an alarm, which has made ...

Control the vertical center of the text in the HTML text box through CSS

When the height attribute of Text is defined, the ...

Two practical ways to enable proxy in React

Two ways to enable proxy React does not have enca...

vite2.x implements on-demand loading of ant-design-vue@next components

1. Use version vite:2.0 ant-design-vue: 2.0.0-rc....

Detailed example of reading speed of js objects

1. Accessing literals and local variables is the ...