kermitvomit kermitvomit - 2 months ago 28
React JSX Question

ReactJS setState not working on first toggle of checkbox

Is there a reason

setState
would not be running to rerender? I've used a
console.log
callback to detect if the state has changed, but to no avail.

Here is the code I'm using. There's more such that the state is a
bool
for a function call, but the basics of the function is here.

export class ExampleClass extends React.Component {
constructor(props) {
super(props);
this.state = {
usingToggleOne: false
};
}
}
toggleforToggleOne(event) {
this.setState({
usingToggleOne: !this.state.usingToggleOne,
});
}

render() {
return(
<input type="checkbox"
onChange={this.toggleforToggleOne.bind(this)} />
}


I'll hit the checkbox the first time and it will tick, but the state doesn't change, but after it'll work normally. Any reasons why? I've had luck using
Object.assign
to get the first tick to work, but I'd rather not use that because it's mutating the state.

Answer

try console.log() in the render() or in the componentDidUpdate() methods as demonstrated in the code below and in this codepen: http://codepen.io/PiotrBerebecki/pen/ZpLNZd

You can also access new state using the optional callback function passed to 'setState'. More info here: http://reactkungfu.com/2016/03/dive-into-react-codebase-handling-state-changes/#solving_the_validation_problem

The state bool changes each time the box is ticked / unticked.

Also, please note the following from the React docs: https://facebook.github.io/react/docs/component-api.html#setstate

There is no guarantee of synchronous operation of calls to setState and calls may be batched for performance gains. setState() will always trigger a re-render unless conditional rendering logic is implemented in shouldComponentUpdate(). If mutable objects are being used and the logic cannot be implemented in shouldComponentUpdate(), calling setState() only when the new state differs from the previous state will avoid unnecessary re-renders.

class ExampleClass extends React.Component {
  constructor() {
    super();
    this.state = {
      usingToggleOne: false
    };

  }

  toggleforToggleOne(event) {
    console.clear();
    console.log('check in toggle before set state', this.state.usingToggleOne);
    this.setState({
      usingToggleOne: !this.state.usingToggleOne
    }, function afterStateChange () {this.useNewState();});
    console.log('check in toggle after set state', this.state.usingToggleOne);
  }

  useNewState() {
    console.log('check in useNewState callback', this.state.usingToggleOne);
  }

  componentWillUpdate() {
    console.log('check in componentWillUpdate', this.state.usingToggleOne);
  }

  componentDidUpdate() {
    console.log('check in componentDidUpdate', this.state.usingToggleOne);
  }

  render() {
    console.log('check in render', this.state.usingToggleOne);
    return(
      <input type="checkbox"
             onChange={this.toggleforToggleOne.bind(this)} />
    );
  }
}