0

I have the following method in a form component:

validateForm () {
    this.setState({isValid: true});
    this.formFields.forEach(field => {
        let isValid = field.ref.current.validateField();
        console.log('Field isValid?', isValid);
        if (!isValid) {
            this.setState({isValid: false});
        }
        console.log('Form isValid?', this.state.isValid);
    });
    return this.state.isValid;
}

When it is called it sets the form state isValid as true. And then loops through the child components we store in the formFields and finds out if any of them are invalid at which point it will mark the form is invalid if any return an invalid response.

Using the console logs I've found that the state for the form is always the previous state console.log('Form isValid?', this.state.isValid); until I call the method again and then it returns the correct state value...

I've seen something similar happen in ActiveRecord in Rails whereby you need to called reload on the model to make sure you're getting the latest state due to caching... Does React have something similar?

Cameron
  • 27,963
  • 100
  • 281
  • 483
  • Does this answer your question https://stackoverflow.com/a/40408976/16732460 – iunfixit Sep 09 '21 at 15:29
  • I'm not sure how necessary `this.setState()` is at the top, but it's asynchronous so you'll have to either move it, or use the callback (not really recommended) – Sterling Archer Sep 09 '21 at 15:30
  • Does this answer your question? [Why calling setState method doesn't mutate the state immediately?](https://stackoverflow.com/questions/42593202/why-calling-setstate-method-doesnt-mutate-the-state-immediately) – Brian Thompson Sep 09 '21 at 15:37

2 Answers2

2
validateForm () {
    let valid = true
    this.formFields.forEach(field => {
        let isValid = field.ref.current.validateField();
        if (!isValid) {
            valid = false;
        } 
    });
    if (!valid) {
        this.setState({isValid: false});
    }
    return valid;
}

Use this code.

setState() is asynchronous. so it will not change its value right after calling setState(). it will only change its value on the next render

sojin
  • 2,158
  • 1
  • 10
  • 18
1

It is because this.setState is not synchronous. It update the state in batches. Example:

this.setState({ isValid: true });
console.log(this.state.isValid);

This will not log true.

To do something only when the state got updated, you can pass a callback as a second parameter to this.setState.

Example:

this.setState({isValid: true}, () => {
//body
})

In your case, insted of setting state, you can set a normal variable value and then change it based on the condition instead of setting state.

validateForm () {
    let valid = true;
    this.formFields.forEach(field => {
        let isValid = field.ref.current.validateField();
        console.log('Field isValid?', isValid);
        if (!isValid) {
            valid = false;
        }
        console.log('Form isValid?', this.state.isValid);
    });
    return valid;
}
Mohit kumar
  • 447
  • 2
  • 10