3

After reading about React, I decided to test some simple ideas in a sample project.But I surprised why setState doesn't work as expected. setState doesn't change state,Even when I am using update add-on.When I change setState to state, it works! I have logged new state object too, and it is correct.I don't know what is wrong! I'll appreciate your help.

import React from 'react';
import update from 'react-addons-update';
class WebFooterSubscription extends React.Component {
    //========================================================
    constructor(props) {
        super(props);
        this.state = {
            formIsValid: false,
            email: {
                value: "",
                focused: false,
                touched: false,
                isValid: false,
                error: "Enter your email"
            },
            mobile: {
                value: "",
                focused: false,
                touched: false,
                isValid: false,
                error: "Enter your mobile"
            }
        };
    }
    //=================================================================
    componentDidUpdate(prevProps, prevState) {}
    //========================================================
    onBlur(event) {
        if ('mobile1' === event.target.id) {
            let newState = { ...this.state,
                mobile: { ...this.state.mobile,
                    value: event.target.value,
                    focused: false,
                    touched: true
                }
            };
            console.log("mobile blur:", JSON.stringify(newState));
            this.setState(newState); // this seems not to work!
        }
        if ('email1' === event.target.id) {
            let newState = update(this.state, {
                email: {
                    value: {
                        $set: event.target.value
                    },
                    touched: {
                        $set: true
                    },
                    focused: {
                        $set: false
                    }
                }
            });
            console.log("email blur:", JSON.stringify(newState));
            this.setState(newState); // this seems not to work!
        }
        this.cmdValidate();
    }
    //========================================================
    onFocus(event) {
        console.log("focus occured");
        if ('mobile1' === event.target.id) {
            let newState = { ...this.state.mobile
            };
            newState.focused = true;
            newState.touched = true;
            this.setState({ ...this.state,
                mobile: newState
            });
        }
        if ('email1' === event.target.id) {
            this.setState({ ...this.state,
                email: { ...this.state.email,
                    touched: true,
                    focused: true
                }
            });
        }
    }
    //========================================================
    cmdValidate() {
        // console.log("length " ,this.state.mobile.value.length);
        if (this.state.mobile.value && this.state.mobile.value.length === 11) {
            this.setState({ ...this.state,
                mobile: { ...this.state.mobile,
                    isValid: true,
                    error: ""
                }
            });
        } else {
            this.setState({ ...this.state,
                mobile: { ...this.state.mobile,
                    isValid: false,
                    error: "Enter your cell phone number correctly"
                }
            });
        }
        if (this.state.email.value) {
            let isValidEmail = true;
            if (isValidEmail) {
                this.setState({ ...this.state,
                    email: { ...this.state.email,
                        isValid: isValidEmail
                    }
                });
            } else {
                this.setState({ ...this.state,
                    email: { ...this.state.email,
                        isValid: false,
                        error: "Your email is not correct"
                    }
                });
            }
        } else {
            this.setState({ ...this.state,
                email: { ...this.state.email,
                    isValid: false,
                    error: "Enter email"
                }
            });
        }
        if (this.state.email.isValid && this.state.mobile.isValid) {
            this.setState({ ...this.state,
                formIsValid: true
            });
        } else {
            this.setState({ ...this.state,
                formIsValid: false
            });
        }
    }
    //========================================================
    onSubmitClick(event) {
        //this.setState({count : this.state.count + 1});
        event.preventDefault();
    }
    render() {
        return (<form name="subscriptionForm" id="subscriptionForm" className="form" method="post">
                                <div className={`form-group ${this.state.email.touched && !this.state.email.isValid ? ' has-danger' : ''}`}>
                                    <div className="col-md-12  ">
                                        <div className="input-group" >
                                            <input id="email1" name="email1" onBlur={(event)=>this.onBlur(event)} onFocus={(event)=>this.onFocus(event)}  className="form-control"  placeholder="email"  type="text" />
                                            <div className="input-group-addon"><img src="assets/images/icons/svg/opened-email-envelope.svg" alt="email" width="24px" height="24px" /></div>
                                        </div>
                                        <div className="help-block" hidden={!this.state.email.focused}>
                                                 {this.state.email.touched && ((this.state.email.error && <span>{this.state.email.error}</span>))}
                                        </div>

                                    </div>
                                </div>
                                <div className={`form-group ${this.state.mobile.touched && !this.state.mobile.isValid ? ' has-danger' : ''}`}>
                                    <div className="col-md-12  ">
                                        <div className="input-group" >
                                            <input id="mobile1" name="mobile1" className="form-control" onBlur={(event)=>this.onBlur(event)}  onFocus={(event)=>this.onFocus(event)}   placeholder="cell phone" type="text" />
                                            <div className="input-group-addon"><img src="assets/images/icons/svg/talking2.svg" alt="cell phone" width="24px" height="24px" /></div>
                                        </div>
                                    </div>
                                </div>
                                <div className="leftButton">
                                    <button type="submit"  onClick={(event)=> this.onSubmitClick(event)}  className="btn btn-primary" >Subscribe</button>
                                </div>
                                    <div>
                                        {JSON.stringify(this.state)}disabled={!this.state.formIsValid}
                                    </div>
                            </form>);
    }
}
export default WebFooterSubscription;
ɢʀᴜɴᴛ
  • 32,025
  • 15
  • 116
  • 110
Behdad
  • 184
  • 3
  • 12
  • Possible duplicate of [Why calling setState method doesn't mutate the state immediately?](http://stackoverflow.com/questions/42593202/why-calling-setstate-method-doesnt-mutate-the-state-immediately) – Mayank Shukla Mar 26 '17 at 09:10

2 Answers2

1
  • setState is a async operation ,so sometimes when you try to access the new-state just after setting it,you dont get the updated state.
  • So in order to access new-state just after setting it, you need to access it through a callback function , which look like this :-

    this.setState({//here you provide new state},()=>{//here you access it})

  • In your case you can access it in this way ,in onBlur Function.

  onBlur(event){
let newState
        if('mobile1'===event.target.id){
            newState= {...this.state,mobile:{...this.state.mobile ,value:event.target.value, focused:false, touched:true}};
            console.log("mobile blur:" ,JSON.stringify(newState));
         
        }
        if('email1'===event.target.id){
             newState = update(this.state, { email: { value: {$set: event.target.value} ,touched: {$set: true},focused:{$set:false}}   });
            console.log("email blur:" ,JSON.stringify(newState));
        }
        this.setState(newState,()=>{this.cmdValidate()})
        
    }
  • hope above solution might solve your problem..... :)
Rajat Gupta
  • 1,864
  • 1
  • 9
  • 17
  • Thank you Rajat.I know that setState is async.but I am not using logging.I've used JSON.Stringify to show whole state in render method.It must finally show state updates in render method. – Behdad Mar 29 '17 at 08:59
0

I'm guessing it's because setState is async and you're logging it immediately after. It'll be updated by the time render is called.

Brigand
  • 84,529
  • 20
  • 165
  • 173