score:124

Accepted answer

You should invoke your second function as a callback to setState, as setState happens asynchronously. Something like:

this.setState({pencil:!this.state.pencil}, myFunction)

However in your case since you want that function called with a parameter you're going to have to get a bit more creative, and perhaps create your own function that calls the function in the props:

myFunction = () => {
  this.props.updateItem(this.state)
}

Combine those together and it should work.

score:0

You can also update the state twice like below and make the state update immediately, this worked for me:

this.setState(
        ({ app_id }) => ({
          app_id: 2
        }), () => {
          this.setState(({ app_id }) => ({
            app_id: 2
          }))
        } )

score:0

Here is React Hooks based solution.

Since React useState updates state asynchronously, check them in the useEffect hook if you need to see these changes.

score:2

I used both rossipedia's and Ben Hare's suggestions and did the following:

checkPencil(){
   this.setState({
      pencil:!this.state.pencil,
   }, this.updatingItem); 
}

updatingItem(){
    this.props.updateItem(this.state)
}

score:2

Ben has a great answer for how to solve the immediate issue, however I would also advise to avoid duplicating state

If a state is in redux, your checkbox should be reading its own state from a prop or store instead of keeping track of the check state in both its own component and the global store

Do something like this:

<p>
    <input
        type="checkbox"
        name="area" checked={this.props.isChecked}
        onChange={this.props.onChange}
    />
    Writing Item
</p>

The general rule is that if you find a state being needed in multiple places, hoist it up to a common parent (not always redux) to maintain only having a single source of truth

score:2

try this

this.setState({inputvalue: e.target.value}, function () {
    console.log(this.state.inputvalue);
    this.showInputError(inputs[0].name);
}); 

showInputError function for validation if using any forms

score:2

As mentioned above setState() is asynchronous in nature. I solved this issue simply using async await.

Here's an example for refernce:

continue = async (e) => {
        e.preventDefault();
        const { values } = this.props;
        await this.setState({
            errors: {}
        });
        const emailValidationRegex = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i;
        if(!emailValidationRegex.test(values.email)){
            await this.setState((state) => ({
                errors: {
                    ...state.errors,
                    email: "enter a valid email"
                }
            }));
        }
   }

score:7

First set your value. after proceed your works.

this.setState({inputvalue: e.target.value}, function () {
    this._handleSubmit();
}); 

_handleSubmit() {
   console.log(this.state.inputvalue);
   //Do your action
}

score:12

It's because it happens asynchronously, so means in that time might not get updated yet...

According to React v.16 documentation, you need to use a second form of setState() that accepts a function rather than an object:

State Updates May Be Asynchronous

React may batch multiple setState() calls into a single update for performance.

Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.

For example, this code may fail to update the counter:

// Wrong
this.setState({
  counter: this.state.counter + this.props.increment,
});

To fix it, use a second form of setState() that accepts a function rather than an object. That function will receive the previous state as the first argument, and the props at the time the update is applied as the second argument:

// Correct
this.setState((prevState, props) => ({
  counter: prevState.counter + props.increment
}));

score:13

When you're updating your state using a property of the current state, React documentation advise you to use the function call version of setState instead of the object.

So setState((state, props) => {...}) instead of setState(object).

The reason is that setState is more of a request for the state to change rather than an immediate change. React batches those setState calls for performance improvement.

Meaning the state property you're checking might not be stable. This is a potential pitfall to be aware of.

For more info see documentation here: https://facebook.github.io/react/docs/react-component.html#setstate


To answer your question, i'd do this.

checkPencil(){
    this.setState((prevState) => {
        return {
            pencil: !prevState.pencil
        };
    }, () => {
        this.props.updateItem(this.state)
    });
}

score:13

On Ben Hare's answer, If someone wants to achieve the same using React Hooks I have added sample code below.

import React, { useState, useEffect } from "react"

let [myArr, setMyArr] = useState([1, 2, 3, 4]) // the state on update of which we want to call some function

const someAction = () => {
  let arr = [...myArr]
  arr.push(5) // perform State update
  setMyArr(arr) // set new state
}

useEffect(() => { // this hook will get called everytime when myArr has changed
// perform some action which will get fired everytime when myArr gets updated
   console.log('Updated State', myArr)
}, [myArr])

score:29

Calling setState() in React is asynchronous, for various reasons (mainly performance). Under the covers React will batch multiple calls to setState() into a single state mutation, and then re-render the component a single time, rather than re-rendering for every state change.

Fortunately, the solution is rather simple - setState accepts a callback parameter:

checkPencil: () => {
   this.setState(previousState => ({
      pencil: !previousState.pencil,
   }), () => {
      this.props.updateItem(this.state);
   });
}

Related Query

More Query from same tag