1

This is my class component:

import React from 'react';

import { Jumbotron, Container, Label } from 'reactstrap';

import './Css.css';

class Settings extends React.Component {

  state = {
    isChecked: false,
  }

  isCheck(e) {
    this.setState({
      isChecked: e.target.checked
    })
    console.log(e.target.checked)
    console.log(this.state.isChecked)
  }


  render() {
    return (
      <div className="margin">
        <Jumbotron fluid>
          <Container fluid>
            <h1 className="display-3">Settings</h1>

            <div className="groupbox">
              <Label className="lead">This is a checkbox</Label>
              <input class="apple-switch" type="checkbox" onChange={e => this.isCheck(e)} />
            </div>

          </Container>
        </Jumbotron>
      </div>
    );
  }
}

export default Settings;

The problem that I have is that the values that I get in the console are inversed.

So when the checkbox is unchecked e.target.checked is false but this.state.isChecked is true, and when the checkbox is checked e.target.checked is true and this.state.isChecked is false.

I don't know why I'm facing this issue.

  • Is there anything that I did wrong?

I tried also to store the e.target.checked to a const checked and then pass it to the setState() but it gives me the same thing.

Any help is appreciated.

hgb123
  • 13,869
  • 3
  • 20
  • 38
Youness Saadna
  • 792
  • 2
  • 8
  • 25
  • Does this answer your question? [React setState not Updating Immediately](https://stackoverflow.com/questions/38558200/react-setstate-not-updating-immediately) TL;DR React state updates are asynchronous and batch processed *between* render cycles, you're simply logging the state from the *current* render cycle versus what is enqueued for the *next* render cycle. If you want to log the state update, use `componentDidUpdate` lifecycle function, or the `setState` callback. – Drew Reese Aug 20 '20 at 23:38
  • @DrewReese no it doesn't. – Youness Saadna Aug 20 '20 at 23:41
  • 1
    Actually, it does... this question is asked nearly daily. I just did a search and that was the first one in the results with the highest upvote count. – Drew Reese Aug 20 '20 at 23:42
  • @DrewReese Is it good to use `this.state.isChecked = e.target.checked` instead of `setState()`? Cause it gives me what I want. – Youness Saadna Aug 21 '20 at 09:15
  • 1
    That would be a state mutation and should be avoided. https://reactjs.org/docs/state-and-lifecycle.html#using-state-correctly – Drew Reese Aug 21 '20 at 09:18
  • @DrewReese I see now, it will not re-render a component. – Youness Saadna Aug 21 '20 at 09:22

2 Answers2

3

The problem is purely a logging one. There is a delay between setting the value and seeing it updated on state. Try:

  isCheck(e) {
    console.log(e.target.checked);
    this.setState({
      isChecked: e.target.checked
    }, () => {
      console.log(this.state.isChecked);
    });
  }

If you need to do something after state has been updated, then put it into a callback function inside the setState call, as above. The reason for this is that setState calls render (that is its main purpose), and React will do that asynchronously, when it's ready.

see sharper
  • 11,505
  • 8
  • 46
  • 65
  • It gives me an error in the `console.log(e.target.checked)`? – Youness Saadna Aug 20 '20 at 23:45
  • 1
    @YounessSaadna Console logs are also asynchronous in nature so the react synthetic event has likely been nullified and returned to the event pool. Just save the checked value in the function, i.e. `const { checked } = e.target;` or persist the event object, `e.persist();` to keep it from being nullified and returned. https://reactjs.org/docs/events.html#event-pooling – Drew Reese Aug 20 '20 at 23:50
  • 1
    console.log is not async (or at least, it's not clear that it is), but the salient point is correct - the event has been lost by the time the callback runs. I've updated the answer. Note that it doesn't really matter though. You aren't interested in the log, you're interested in setting the value, which was working to begin with. You were just misled by the log. – see sharper Aug 20 '20 at 23:59
1

According to the doc

Think of setState() as a request rather than an immediate command to update the component

setState() does not always immediately update the component. It may batch or defer the update until later. This makes reading this.state right after calling setState() a potential pitfall. Instead, use componentDidUpdate or a setState callback (setState(updater, callback)), either of which are guaranteed to fire after the update has been applied

So setState() here is asynchronous, so in your case, to see the effect, just use a callback (here I use arrow function to maintain the context of this)

isCheck(e) {
  this.setState(
    {
      isChecked: e.target.checked,
    },
    () => {
      console.log(e.target.checked)
      console.log(this.state.isChecked)
    }
  )
}
hgb123
  • 13,869
  • 3
  • 20
  • 38