简体   繁体   中英

What is the correct way to set state in React

Honestly, this is my day 1 in ReactJS. I'm learning some small-small things like state . I've created a small program for the toggle button. It will simply display "Hello world!" or display nothing when the button is toggled. There's one thing that I didn't understand. My code gives me an error when I use this syntax:

  toggleHandler() {
    const currentStatus=this.state.display;
    this.setState({
      display: !currentStatus
    })
  }

this.state is undefined

But the same code works perfectly If I change the syntax to a fat arrow function:

  toggleHandler=()=> {
    const currentStatus=this.state.display;
    this.setState({
      display: !currentStatus
    })
  }

I'll not waste your time. I've created an stackblitz . Experts on the internet say that any call to this.setState() is asynchronous. So I tried using call back function and IIFE but got myself more confused and over-complicated. Please correct me. I'm sorry this is a very childish question.

There are a couple of ways.

One is to add in the constructor. ES6 React.Component doesn't auto bind methods to itself . You need to bind them yourself in constructor. Like this

this.toggleHandler = this.toggleHandler.bind(this);

Another is arrow functions toggleHandler = (event) => {...}.

And then there is onClick={this.toggleHandler.bind(this)}

reference

Yes, any setState call is asynchronous. You can check your log that it changes his status but not manipulate the dom. For manipulating the dom Any asynchronous call should be via a callback function.

you can bind any state with this arrow function or this.state.bind(this).

What the error message is telling you is that the this object doesn't contain a property called state . What exactly this refers to is a constant source of confusion in JS, except when inside an arrow function. Inside an arrow function, this always refers to the context the arrow function appears in.

The issue here is in the first example, this refers to the context sent to the handler by the onClick event. This context does not contain a state property. However, inside the arrow function, the this keyword will refer to the JavaScript class that your arrow function exists in. This class does have the state property.

To get around this, you can use bind (which outputs a copy of your function with the context set to whatever you supply it with. Or just use arrow functions. If it were me I would take the latter approach since this has better defined and more consistent behaviour inside an arrow function. If you do want to use bind , you would do this in your event handler declaration like so:

onClick={this.toggleHandler.bind(this)}

The way you can use functions and previous state.

1- Binding in constructor

constructor() {
    this.toggleHandler=this.toggleHandler.bind(this);
  }

can define like this

  toggleHandler=()=>{
    this.setState(prev=>({
      display: !prev.display
    }))
  }

2- arrow function (don't need to bind in constructor)

  toggleHandler=()=>{
    this.setState(prev=>({
      display: !prev.display
    }))
  }

3- Inline binding

<Button onClick={this.toggleHandler.bind(this)}>Toggle</Button>

function code

  toggleHandler=()=>{
    this.setState(prev=>({
      display: !prev.display
    }))
  }

4- Inline arrow function

 <Button onClick={()=>this.toggleHandler()}>Toggle</Button>

function code

  toggleHandler=()=>{
    this.setState(prev=>({
      display: !prev.display
    }))
  }

Note - Recommended to avoid inline functions for better performance

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM