React--7: three core attributes of the component 1:state

Posted by igorlopez on Mon, 27 Dec 2021 15:41:03 +0100

1. Simple and complex components

Simple component: no state
Complex component: state

So what is state?

2. state

In fact, the title is: the three core attributes of components (instances).
Only class components have instances, and functional components are not qualified at all. In order to solve the problem of functional components, react introduced hooks.

Use of state: let's take an example and click to change whether the weather is hot or cool

2.1 creating components

Do we want to create class components or functional components?
Class components, of course.

// 1. Create class components
class Weather extends React.Component{
    render(){
    console.log(this)

        return <h2>It's very hot today</h2>
    }
}
// 2. Rendering
ReactDOM.render(<Weather/>, document.getElementById('root'))

Then we need to define a variable isHot to change whether it is hot or cool. State is on an instance of the class. If we want to add variables to state and initialize the class instance, we need to write a constructor.

class Weather extends React.Component{
    constructor(???){
        
    }
    render(){
    console.log(this)

        return <h2>It's very hot today</h2>
    }
}

2.2 adding constructors

So what parameters need to be passed in the constructor? This depends on the parameters passed by the instance object. However, this is created by React and we can't see it.

We went to the official website and it passed props. Do you need to write super? Yes, this is the type of regulation.

// 1. Create class components
class Weather extends React.Component{
    constructor(props){
        super(props)
    }
    render(){
    console.log(this)

        return <h2>It's very hot today</h2>
    }
}

2.3 adding variables / attributes

state to be written as an object

 constructor(props){
        super(props)
        this.state = {
            isHot:true
        }
    }

Now there is our isHot in the state on the instance object

Next, we just need to take out this value and render it

// 1. Create class components
class Weather extends React.Component{
    constructor(props){
        super(props)
        this.state = {
            isHot:true
        }
    }
    render(){
    console.log(this)

        return <div>

            <h2>It's a fine day today
            {
                this.state.isHot ? 'scorching hot':'pleasantly cool'
            }
            </h2>
        </div>     
    }
}

2.4 change the state value setState

Click the button to change the value

2.4. 1 original writing

Add id attribute to h2 tag. Use method: addEventListener or onClick

// Modular syntax in ES6
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';

// 1. Create class components
class Weather extends React.Component{
    constructor(props){
        super(props)
        this.state = {
            isHot:true
        }
    }
    render(){
    console.log(this)

        return <div>

            <h2 id="title">It's a fine day today
            {
                this.state.isHot ? 'scorching hot':'pleasantly cool'
            }
            </h2>
        </div>
        
            
    }
}
// 2. Rendering
ReactDOM.render(<Weather/>, document.getElementById('root'))
// Native method 1
const title = document.getElementById("title")
title.addEventListener('click',()=>{
	console.log("The title was clicked")
}
// Native method 2
title.onClick=()=>{
	console.log("The title was clicked")
}

Although the two methods can realize click events, they both use React to write as few native js methods as possible.

2.4. 2 write it in the label

This, of course, is also a native method. We write a new button tag and add onclick inside. Then write a demo method.

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';

// 1. Create class components
class Weather extends React.Component{
    constructor(props){
        super(props)
        this.state = {
            isHot:true
        }
    }
    render(){
    console.log(this)

        return <div>

            <h2 id="title">It's a fine day today
            {
                this.state.isHot ? 'scorching hot':'pleasantly cool'
            }
            </h2>
             <button onclick="demo()">change weather</button>
        </div>
        
            
    }
}
// 2. Rendering
ReactDOM.render(<Weather/>, document.getElementById('root'))

function demo(){
	console.log("The button was clicked")
}

We will find that it reports an error because onclick cannot be used. So what do we use? Use onclick and React to turn the original events into hump rules.
So we have to change it to

 <button onClick="demo()">change weather</button>

2.4. 3. Does the function need parentheses

We found that the "button is clicked" has been printed without clicking

So why? React helps us create a Weather instance and calls render through the instance. The < button onClick="demo()" > change Weather < / button > code is executed. To assign the return value of the function, onClick="demo()" is an assignment statement. Assign the return value on the right to onClick as a callback. What is the return value of the demo function? It's undefined. Clicking now has no effect.

Therefore, you need to delete the parenthesis onClick="demo", which means that the function on the right is given to the onClick event as a callback, and the function will be called only when it is clicked

Now click the button again to achieve the effect we want.

2.4. 4 change the value of isHot in the demo function

We deconstruct the assignment and get isHot

function demo(){
 const {isHot} = this.state
 console.log(isHot)
}

It was found that the report was wrong. state is not defined, so what is the root cause? It's this.

Why is there no this?
First of all, this function is our custom function, and Babel is in strict mode when converting our jsx to js. It does not allow this of a custom function to point to window.

🤔 What if we can't get the instance object of the component in our custom demo function?
We define a that variable in the outermost part, and then assign this, that is, the instance object, to that in the constructor. Finally, print that in the function

Although this is achieved, it is not perfect.
We put the demo method into the class and found that the function reported an error, because it can't be written in the class.

Just remove function

Now the demo is placed on the prototype object of the class for use by the instance object.
When a demo is called through a Weather instance, this in the demo is the Weather instance.

You don't need that at this time. Now an error will be reported. The demo function is undefined. Because the demo is under the instance object, you need this demo

After clicking, an error will still be reported because this is undefined

2.4. 5 this point of user-defined function

At this time, onClick={this.demo} does not call the demo method at all, but finds the demo along the prototype chain through the instance object of the class, and then gives this function to onClick as a callback. Calling functions directly from the heap is not invoked from the instance object at all. Methods in the class turn on local strict mode by default. Therefore, this is undefined at this time.

Using bind

 this.demo = this.demo.bind(this)
  • In essence, it is an assignment statement. First look at the right. In fact, there is no demo in the instance, so why not report an error? It will find the function on the prototype according to the prototype chain, which will find the function we defined.
  • Once the code on the right is run, there will be a function, and this of this function successfully becomes the instance object of Weather.
  • On the left, we put this function in the instance itself and give it a name, this demo.

At this point, when we print this in the function, we will find that we also have a demo method. So is each click and call executed by itself or on the prototype 🤔 ? According to the prototype chain, you have found it on yourself, so you won't find it on the prototype again.

Can the demo method on the prototype be deleted 🤔 ? Of course not. Because there is a demo method on the prototype, we can generate a new instance and hang it on the instance itself.

2.4.6 setState⁄

Get the value of the original isHot in the demo function. And reverse it and assign it back.

  demo(){
        const {isHot} = this.state
        this.state.isHot  = !isHot 
    }
}

No change in how you click. So let's print out the console Log (this. State. Ishot) found that the value did change

The isHot value has changed, but the page does not change. Let's take a look at the react developer tool. No matter how we click on this value, it remains the same. React does not recognize our operation.

⚠️ : The status cannot be changed directly. API: setState is required
this.state.isHot = !isHot is ❌ How to write. The following is correct.

 demo(){
        const {isHot} = this.state
        this.setState({isHot:!isHot})     
    }

Then think about it 🤔
Is this setState merged or overwritten?
Let's add a wind variable to state. When changing isHot, whether the value of wind is lost or not is merging, otherwise it is overwriting.

  this.state = {
            isHot:true,
            wind:"wind"
       }
       
 	demo(){
        const {isHot} = this.state
        this.setState({isHot:!isHot}) 
        console.log(isHot)
       
    }


So it's a merger.

3. Streamline code

3.1 remove the constructor

Why write constructors?
Because some initialization operations need to be done. Do you feel like there's no place to write it in the constructor.
Class can write assignment statements directly. Therefore, assigning a value to state does not have to be written in the constructor.

state = {
        isHot:true,
        wind:"wind"
    }

You can find it undefined again. Because the demo function is placed on the prototype object of Weather.

3.2 transformation of user-defined functions

First, most of our custom methods are used as event callbacks.
Let's change this function: now it's an assignment statement. Now the demo is placed on the Weather instance itself, not on the prototype.

 demo = function(){
        const {isHot} = this.state
        this.setState({isHot:!isHot}) 
        console.log(isHot)
       
    }


We clicked again, but it still didn't solve the problem.
Next, we replace the function with an arrow function. I found it.

demo=()=>{
        const {isHot} = this.state
        this.setState({isHot:!isHot}) 
        console.log(isHot)
       }

🤔 So why that?

  • There is no this in the arrow function. Will an error be reported if this is used in the arrow function? No, he'll look for this in its outer function
    To use. Find the outside, and you'll find the area inside the class.
  • Can we print this in the blank area? You can see that the error has been reported. Because this is a class, you can't write code casually.


So what do we think of this in the blank area? Can't see it? We just said that this in the arrow function is the point of this in its outer layer. So this we print in the arrow function is this in the blank area. It can be found that it is an instance object of the component.

3.3 complete code

After simplification, there is no need to write a constructor. The user-defined method should use the form of assignment statement + arrow function

class Weather extends React.Component{
    state = {
        isHot:true,
        wind:"wind"
    }
    render(){
    console.log(this)

        return <div>

            <h2>It's a fine day today
            {
                this.state.isHot ? 'scorching hot':'pleasantly cool'
            }
            </h2>
            <button onClick={this.demo}>change weather</button>
        </div>
    }

    demo=()=>{
        const {isHot} = this.state
        console.log(this,"this")
        this.setState({isHot:!isHot}) 
        console.log(isHot)
       
    }
}

Topics: React