Component state

State is simply referred to as data, similar to props, but state is private and fully controlled by the current component. Therefore, component state refers to the data maintained by a component itself.

We also mentioned a very important point earlier: data-driven UI. It simply means that what is displayed on a page is completely state controlled, which is the idea of MVVM. UI changes are left to the framework itself, we just need to manage the “data (state)”.

How do you manage state in React? This is the focus of this article, and of the entire React study: component state management.

The basic use

The use of state is very simple. We declare an object named state in the class. The element in the object is the state data maintained by the current component.

Import React, {Component} from 'React' export class States extends Component { 'xiling', age: 18} render() {return (<> <h2>state </h2> {/* use this.state.xx to get data */} <p>{this.state.name}</p> <p>{this.state.age}</p> </> ) } } export default StatesCopy the code

Previously we said that the state data can control the interface, so how can we modify the state to make the interface change?

Modify the state of

The most straightforward way to change the value of state is to use this.state={} directly. This. State ={} does not work when the button is clicked.

React provides a special this.setstate ({}) method. We need to call this.setState({}) to pass in the data that needs to be changed in order to properly change the value of state.

As for why, we need to understand the React data flow, so we won’t go into details here, just remember this rule.

Import React, {Component} from 'React' export class States extends Component { 'xiling', age: 18} // Arrow function changes = ()=>{// console.log(22) // this.state.name = 'xiling' // error: this.setState({name:' xiling'})} Render () {return (< > < h2 > < / h2 > state state {/ * use this. State. Xx to get data * /} < p > {this. State. The name} < / p > < p > {this. State. The age} < / p > <button onClick={this.changes}> change state</button> </>)}} export default StatesCopy the code

Once the value of state is changed, the use of state in JSX automatically changes. The setState method is a property (method) in the class, and we need to use this to get it. Therefore, the event binding handler needs to use the arrow function to fix this, and must not use the ordinary function (method) declaration. Otherwise, an error will be reported because the method cannot be found.

One-way data flow from top to bottom

Questions about data flow are typical questions that come up frequently in the interview. Generally, the interviewer will directly ask: “How do you understand one-way data flow?” .

Note that this is not a single individual problem, but rather a combination of data flow problems, to which you need to explain:

  • What is data flow?
  • Why is it top-down?
  • What does one-way data flow mean?
  • Why is it one-way? Can’t it be a two-way data flow?
  • What does one-way data flow do?

Once you break the question apart, you’ll find that almost every word the interviewer asks you needs to be explained. That’s a big question, Boa!

So, how do I solve this?

To be honest, there is no standard answer, because the question of data flow involves the design concept of the framework itself, which requires you to have a deep understanding of the design of the framework, and you need to look at the problem from the perspective of the framework author. However, for beginners, this question is obviously out of the ordinary.

Fuck off. That’s so important. I can’t learn, can I? No, you have to learn it many times. This is just the first time.

Before we begin, let’s take a look at some plain JS code:

var datas = {
  name:'lisi',
  age:18
}

var l1 = datas
var l2 = l1
var l3 = l2

l1.age = 20
console.log(l1.age,l2.age,l3.age) // 20 20 20

l3.age = 26
console.log(l1.age,l2.age,l3.age) // 26 26 26
Copy the code

You’ll notice that whenever we change the age property of that variable, the rest of the data will change.

The reason is simple: everyone shares the same memory data. However, before and after the assignment, we can regard L3 node as grandson, L2 node as father, and L1 node as grandfather.

When the data of any node changes, the data of all nodes will change, and we can regard this phenomenon as the flow of data on the “variable node”. However, such data flow is bidirectional. Take L2 as an example. As long as the data changes, L1 node of the upper layer and L3 node of the lower layer will change with it.

Although this example is not appropriate, the same principle applies to the React component. The flow of data is the transfer of data between components. The value transfer between components was explained at length.

So, we add a “one-way” attribute in front of the data flow, called “one-way data flow” what does it mean? In fact, it is easy for you to understand now, which means that data changes at one node only affect other nodes in one direction.

What about top-down? Even simpler, data only affects nodes at the next level, not nodes at the previous level; As explained in the above example, if L2 data changes, only L3 will be affected, not L1 or other nodes.

This is called “top-down one-way data flow.” In the React framework, one-way data flows are explicitly defined: the flow of data is regulated, and data is passed and updated from the outer component to the inner component.

So, in the specific code implementation, how is it reflected? Cuihua, code:

The diagram is a little hard to see, so let’s look at the code demo:

// ========== App ============ import React, { Component } from 'react' import C1 from './C1' export class App extends Component { state = { name: } render() {return (<div> <h1>App</h1> <p> App< b style={{color: RGB (74, 74, 74); "red" }}> {this.state.name} </b> </p> <C1 toC1={this.state.name}></C1> </div> ) } } export default App // ========== C1 ============ import React, { Component } from 'react' import C2 from './C2' export class C1 extends Component { render() { return ( <div> <h2>C1</h2> <p> "red" }}> {this.props.toC1} </b> </p> <C2 toC2={this.props.toC1}></C2> </div> ) } } export default C1 // ========== C2 ============ import React, { Component } from 'react' import C3 from './C3' export class C2 extends Component { state = { name: this.props.toC2 } changes = () => { this.setState({ name: Math. The random ()})} render () {return (< div > < h2 > C2 < / h2 > < button onClick = {() = > {this. Changes ()}} > change < / button > < p > < p style={{color: RGB (51, 51, 51); "red" }}> {this.state.name} </b> </p> <C3 toC3={this.state.name}></C3> </div> ) } } export default C2 // ========== C3 ============ import React, {Component} from 'react' export class C3 extends Component {render() {return (<div> <h2>C3</h2>): <b style={{ color: "red" }}> {this.props.toC3} </b> </div> ) } } export default C3Copy the code

Finally, let’s explain why? What’s the use?

In fact, this is the core of the problem, different technical understanding, there will be different Angle of interpretation, HERE is only one opinion, you listen to.

Let’s imagine this scenario:

The data of the parent component is passed to the child component through props, and the child component updates the props, causing the data of the parent component and other associated components to be updated, and the UI rendering to be updated along with the data. Undoubtedly, this will cause serious data disorder and uncontrollable.

So most frameworks deal with this. React allows Props to be read-only, not mutable. You can’t update data directly through this.state. You need to update data through the special this.setstate () method provided by React.

One-way data flow is actually a kind of framework itself to restrict the flow of data.

Let’s talk about that for now, but the more we learn, the more we experience, the deeper we’ll understand it, the more we’ll see it from a more comprehensive perspective.

Asynchronous setState

Is setState asynchronous or synchronous?

This is a classic interview question that is often asked in interviews, but before we get into the asynchronous nature, we need to be clear that at the API level, it is a normal function that is called to execute, naturally synchronous API. So, when I say synchronous and asynchronous, I mean when the STATE changes after the API call or when the DOM is updated, synchronous or asynchronous.

Let’s start with a piece of code:

import React, { Component } from 'react' export class States extends Component { state = { name:"lisi", age:18 } fun= ()=>{ this.setState({ name:'xiling' }) console.log(this.state.name) } render() { return ( <div> <h2>State Component < / h2 > < p > {this. State. The name} < / p > < button onClick = {() = > {this. Fun ()}} > me < / button > < / div >)}} export default StatesCopy the code

The function of the code is very simple, is to click the button, modify the name property value of the state, the event handler, after calling the setState method, and print the value of state to the console, run the code and you can see that the value in the Dom has changed, This.setstate () is called asynchronously, and the rest of the code is executed immediately after the call. Therefore, the console prints the result before the change.

Therefore, we can be sure that this.setstate () is indeed the code that the asynchronous call executes.

Note that at this point, you can treat this.setState() as normal asynchronous execution code (again, JSX is JS).

So what if I want to tweak my code to get asynchronous execution results? If this is normal asynchronous code, consider that the this.setstate () method also provides a second argument. We can pass in a callback function that will be executed after the asynchron ends.

  fun= async ()=>{
    await this.setState({
      name:'xiling'
    },()=>{
      console.log(this.state.name)
    })
  }
Copy the code

Callbacks handle asynchronous results in traditional asynchronous coding, but one of the biggest problems with asynchronous callbacks is “callback hell.” So since it’s asynchronous, can we just wrap a Promise?

Yes, of course, but encapsulating a Promise is a bit complicated. The simplest way is to implement it with the asynchronous call function async/await in ES 2017. We can directly modify the event handler function, and the specific syntax rules are as follows:

 fun= async ()=>{
    await this.setState({
      name:'xiling'
    })
    console.log(this.state.name)
  }
Copy the code

SetState execution logic

What does the logic need to be handled when using this.setState() to make a state change? The first argument to this.setstate () can be handled by a function, but the function must return a state object as follows:

Fun () = = > {enclosing setState ((state) = > {/ / function logic code... Return {age:returnData}})} return {age:returnData}}Copy the code

So this.setState() can accept both an object parameter and a handler. What’s the difference between the two?

In the time handler, we use this.setState() twice to modify state.

Two functions perform operations:

fun = ()=>{ this.setState((state)=>{ return { age:state.age+2 } }) this.setState((state)=>{ return { age:state.age+3 } })}Copy the code

The function in this.setstate () is executed twice, changing the value of state. We are using the same code logic to modify the operation using object data:

  fun = ()=>{
    this.setState({
      age:this.state.age +2
    })
    this.setState({
      age:this.state.age +3
    })
  }
Copy the code

The result shows that this.setstate () is executed only one last time.

If this.setstate () is a function, the function will execute from top to bottom, whereas if it is an object, React will merge multiple calls to this.setstate () into one execution, and replace the previous change with the last change if the same value is changed.

Keep this in mind in your project code to avoid unexpected logic bugs.

Of course, you may have noticed that after all the talk about component state, all of the experimental coding is done in the class component. Is the function component the same as the class component?

Mm ~ O ( ̄▽ ̄)o… , because state is a feature in the class component, and state in the function component needs to have the knowledge of Hook feature as a foundation, so temporarily leave a hole, waiting to be filled in later.