React uses data in many places, which is called state in React. We needed a way to manage state, and state-related methods were born. State should be required to have two basic functions. First, it can store certain values that can be used by React, and second, it can be listened to and re-rendered when react changes it. Here’s how state is written in class and function components:

Class components

Class ClassComponent extends React.Com {constructor(props){super(props)} // Render (){return (){class class component extends React.Com {constructor(props){super(props)} }}Copy the code

SetState we are commonly used to change state, can directly transfer inside an object to be altered, can also pass a callback function, note that at this point if the incoming is object, the React just do a layer of shallow copy, rather than a deep copy, so if you have any other object in the object at this time to change the React cannot know for rendering. This method essentially passes in a new value and overwrites the original value. If the value is the same as the original value, React will not render.

React why bother to change the value directly? Because in React, there’s a concept called variability. React knows what’s happening by changing the state in setState, so it renders. If it changes state directly,React won’t know it, so it won’t render. In short, it doesn’t have two-way data binding like VUE does.

The constructor function does two main things:

  • Initialize the value of internal state in order to assign the this.state object
constructor(props){
    super(props)
    this.state = {n:12}
}

render(){
    return (
        <div>
                <h1>THE TIME IS {this.state.n}</h1>
        </div>
    )
}
Copy the code

Note that we can’t write setState here. React can also be set outside, i.e

state = {n:12}

render(){
    return (
        <div>
            <h1>THE TIME IS {this.state.n}</h1>
        </div>
    )
}
Copy the code
  • Bind the instance to the event handler function
constructor(props){
    super(props)
    this.addNum = function(){fn()}.bind(this)
}

render(){
    return (
        <button onClick={this.addNum}>+1</button>
    )
}
Copy the code

React uses a new method instead of this method:

addNum = ()=>{
    fn()
}

render(){
    return (
        <button onClick={this.addNum}>+1</button>
    )
}
Copy the code

So the above constructor inherits the superclass method without writing at all.

Function component

Import {useState} from "react" function FunctionComponent(){const [data,setData] = useState(" initial value you want to pass in ") return ( <div>SHOW DATA {state}</div> ) }Copy the code

The setData function here is similar to setState, but it can only be used to change the state of data, passing in a callback function when it needs to be changed. The function takes the previous value and returns the value to be changed. This method essentially requires passing in a new object to change the value of the object before React. It is also possible to write the changed value directly, which by default corresponds to the current object and changes its value. This method is much simpler than the original setState method, but the trouble is that if you have multiple data, you need to pass in multiple useState values rather than passing in multiple values at once. In most cases, though, Redux handles data management, so React itself doesn’t need to be a concern

The pit of setState

A common problem encountered when changing the React component state is merging setState values. Look at the following questions:

this.addNum = function () {
            this.setState({num:this.state.num+1})
            this.setState({num:this.state.num+1})
            this.setState({num:this.state.num+1})
        }.bind(this)
Copy the code

When the addNum function is triggered, num is incremented by 1. It didn’t add 3 like we thought it would. React itself explains this

Calling setState is actually asynchronous — don’t expect this.state to map to the new value immediately after calling setState

Here’s the explanation:

  1. No matter how many times setState is called, the update will not be performed immediately. Instead, the state to be updated is stored ‘_pendingStateQuene’ and the component to be updated is stored ‘dirtyComponent’;
  2. When the root component didMount, the batch mechanism is updated to false. Fetch state and component from ‘_pendingStateQuene’ and ‘dirtyComponent’ for merge update;

When React is executed, the setState to be updated will be stored in an array to improve performance. When the React synchronization code is executed, the setState will be extracted from the array and rendered before the update. SetState ({num:this.state.num+1}); setState({num:this.state.num+1}); Because of this mechanism, we make setState look like asynchronous code, but it actually executes synchronously, so if we change the previous synchronous code to asynchronous, we get the result we want

this.addNum = function () {
            setTimeout(()=>{ this.setState({num:this.state.num+1}) },0)
            setTimeout(()=>{ this.setState({num:this.state.num+1}) },0)
            setTimeout(()=>{ this.setState({num:this.state.num+1}) },0)
        }.bind(this)
Copy the code

At this point, the value is directly increased by 3, because asynchronous code is held temporarily while the code is executing. It’s done when all the synchronized code is done, when the batch mechanism is done, so all three functions are done, so it’s added by 3 as far as we can think of, and we’ll add more if we get more