Get state right after setState()

Viewed 4844

I know setState() does not immediately mutate this.state. So in the code below, checkbox is always unchecked after clicking the button. How to fix this?

handleClick = () => {
  this.setState({tick: !this.state.tick})
}

render() {
  return (
    <button type='button' onClick={() => this.handleClick()} >
      <input type="checkbox" value={this.state.tick} />
      Tick here
    </button>
  )
}
2 Answers

use checked instead of value:

<input type="checkbox" checked={this.state.tick} />

from the spec:

checked: Boolean; if present, the checkbox is currently toggled on

value: The string to use as the value of the checkbox when submitting the form, if the checkbox is currently toggled on

ic3b3rg's answer highlights what needs to be changed in the code for the checkbox to work. I'm going to highlight a few other things that could be improved.

  1. Checkbox check state should be controlled with checked attribute

  2. Don't declare your event handlers with arrow functions as it will create a new anonymous function during every single render. It's a good idea to bind a function to the class and pass it to the event handler.

Something like this

constructor(props) {
  super(props);
  this.handleClick = this.handleClick.bind(this);
}

handleClick() {
  ...
}

// render
<button type = 'button' onClick = {this.handleClick} >
  1. When you want to update state based on existing state value, it's usually not a good idea to call this.state.key directly in your setState function as setState is an async call and you can't exactly say what the value of your current state will be. Instead, if you use this.setState((prevState, props) => ({}) callback, your state value will be updated based on what your existing state value was during invocation.

Change this

this.setState({tick: !this.state.tick})

to

this.setState((prevState, props) => ({
  tick: !prevState.tick
}));

Here's a full working example

class Example extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      tick: false
    };
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    // when updating state values from existing state values
    // you should use not use value: !this.state.value directly
    this.setState((prevState, props) => ({
      tick: !prevState.tick
    }));
  }

  render() {
    return (
      <button type = 'button' onClick={this.handleClick} >
        <input type = "checkbox" checked={this.state.tick} />Tick here
      </button>
    );
  }
}

ReactDOM.render( <
  Example / > ,
  document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="react"></div>

Related