SoFunction
Updated on 2025-03-09

Detailed explanation of this pointer in React

I plan to record the record and generally count the problem pointed to by this in React. The specific process is based on three elements of the event: cause, process, and result. Hahahahahaha!

cause:

As we all know, React is designed to be responsive, and the page will be rendered and updated without manipulating the DOM or manipulating the data.

The data is updated as soon as it changes. Is it updating all DOMs? Of course not, re-render what changes. Then we need to compare the DOM before and after the data changes. Direct comparison of real DOM? This will have very low performance. React compares virtual DOM, which is also an object, but compared to real DOM, it has many properties and is more "light".

How to write a virtual DOM? In native JS, we can use the () method to create nodes. It can also be passed in React (component, props, children), but this writing method can be dazzling if it encounters multi-layer nesting. So JSX "come out of nowhere". JSX is actually a syntactic sugar, but it is more convenient for us to use and can be written directly into the form <p >hello</p>.

But the problem is coming again! The JSX syntax is not recognized by webpack. Webpack can only process files with .js suffix names by default, so it is necessary to use the JavaScript compiler Babel, and babel has enabled strict mode **

import React, { Component } from 'react'

export default class index extends Component {
    // speak(){
    // (this)//Output undefined    // }
    speak = () =&gt; (this)//Output this component    render() {
        return (
            &lt;div&gt;
                &lt;button onClick={}&gt;Button&lt;/button&gt;
            &lt;/div&gt;
        )
    }
}

This essentially points to its caller. This is bound when the function is run. Ordinary functions in JS are called by window, so it points to window, and after the strict mode is turned on, it is undefined.

(function(){
    (this)//window
})()

The event passed in JSX is not a string (the event is listened to in native JS, using the form of a callback function, and the string variable is passed to the listening event in Vue), but a function (such as: onClick={} above). At this time, onClick is an intermediate variable, and the function is finally called by React. Because the strict mode is enabled, this is undefined, so this pointer in the processing function will be lost.

go through:

In fact, what we need is that this pointing to the current instantiated object will undoubtedly make the code writing much easier. There are two places in the class component that point exactly to the current instantiated object.

1. Constructor

This in the constructor in the class component points to the instance object, which is a feature of the ES6 class.

As we all know, there is no concept of classes in Javascript like C++ and JAVA. The implementation of ES6 class is also based on prototype chains.

Instantiating an object before ES6 should be like this:

function Animal(name, age) {
   = name
   = age
}
 = function () {
  ()
}
const Dog = new Animal('dog', 3)
()  //Dog will be printed on the console

The new operator first generates an empty object {}, and then generates a this pointer, pointing this pointer to this empty object; when running the constructor, it is equivalent to dynamically adding attributes to this object like {}.name=dog,{}.age=3. Finally, pay the generated object to Dog,

When we use ES6 class to declare the above class, the code is as follows:

class Animal {
  constructor(name, age) {
     = name
     = age
  }
  say() {
    ()
  }
}
const Dog = new Animal('dog', 3)
()  //Dog will be printed on the console

The class implementation should be very different from the above, so this points to the instance object.

function

This in the render function also points to the instance. Why?

First of all, the render method is on the prototype of the class component. When React finds that the component is defined by class, the instance of the class will be new later. Note that this instance is created by React for you new. Then the instance calls the render method to convert the virtual DOM to the real DOM. Therefore, this in render points to the instance, after all, it is called by him! , Similarly, render is a life cycle hook, and this in other life cycle hooks also points to the instance component.

and arrow functions

To solve this problem, you need to have two knowledge storage

(1)bind
call apply bind is defined on the function prototype and is used to change the point of the function this. The first parameter passed in is this. The subsequent parameter is the parameter of fun1

the difference:

  • The function passed to the call and bind can pass multiple apply and put parameters into an array
  • call and apply return the function executed immediately, bind returns the new function, bind()()() is also executed immediately
  • After using bind to this, this in the function cannot be changed no matter who calls it
let aa = {
    fun1: function(a,b){
        (this)
        (a-b);
    }
}        
let bb = {
    fun2: function(a,b){
        (this)
        (a+b);
    }
}

aa.(bb,11,22);//bb-11
bb.(aa,[11,22]);//aa 33
aa.(bb,11,22)();//bb -11

(2) Arrow function
Arrow function: Arrow function does not create its own execution context, so this in the arrow function is the outer layer this, and it will look for this layer in the outward scope until there is a definition of this

const A = {
    arrow:() =>{
        (this)//window
    },
    func:function(){
        ()//window
        (this)//A
        setTimeout(() => {
            (this)//A
        });
    }
}
()
()

result:

I know how to solve it, hehe!

Method 1: Use bind in the constructor

import React, { Component } from 'react'

export default class index extends Component {
    constructor(){
        super()
         = (this)
        /*Solve this problem in the class: = (this), this in the constructor points to the instance object by default.
       The instance object looks for the fnc function on the class prototype through the prototype chain, and points this to the instance object through the bind function, and returns a new function
       Then give this new function to the instance and name it fnc*/
    }
    speak(){
        (this)//Output the current instance object    }
    render() {
        return (
            &lt;div&gt;
                &lt;button onClick={}&gt;Button&lt;/button&gt;
            &lt;/div&gt;
        )
    }
}

Method 2: Assign arrow function to attributes of class

import React, { Component } from 'react'

export default class index extends Component {
    speak = () =&gt;{
        (this)
    }
    render() {
        return (
            &lt;div&gt;
                &lt;button onClick={}&gt;Button&lt;/button&gt;
            &lt;/div&gt;
        )
    }
}//If you need to pass parameters, you can use the idea of ​​currying function

Note: There are differences in performance

Using arrow functions to solve the problem will be relatively low because arrow functions are not methods, they are anonymous function expressions, so the only way to add them to a class is to assign values ​​to attributes. When introducing the ES6 class, we can see that the ES class handles methods and properties in a completely different way.

Methods are added to the prototype of the class, rather than defined once per instance.

The class attribute syntax is syntax sugar assigned to each instance for the same attribute, and it will actually be implemented in the constructor as follows:

    constructor(){
        super()
         = () => {(this)}
    }

This means that when a new instance is created, the function will be redefined, losing the advantage of the JS instance sharing prototype method. Method 1, just one more step in binding operation when generating an instance, which has great advantages in efficiency and memory usage.

The above is a detailed explanation of this pointing in React. For more information about this pointing in React, please follow my other related articles!