简体   繁体   中英

React. Why this.state does not updates correctly?

So, I try to run the function by condition: if I got an Error in the catch method.

To do this, I implement the this.state.loginError in component state, that will change on true if we got an Error. So, and after error - the this.state.loginError comese back with true (and this is also I saw in console.log), but after state changes - my function loginError(target) does not want to start anyway.

See my code and logs below, please:

class LoginPage extends Component {
    constructor(props) {
        super(props);
        this.state = {
            navigate: false,
            loginError: false,
        }
    }

    handleSubmit = (e) => {
        e.preventDefault();

        axios.post('http://localhost:3016/auth/login', userLogin, {withCredentials: true})
            .catch(err => {
                    this.setState({
                        loginError: true
                    });
                    console.log(this.state.loginError);  // gives `true`
            });

            if (this.state.loginError) {
                console.log('Error!') //does not work
                loginError(target);
            }
    };

Because axios.post is asyc function, and at first fires your if condition, and after .catch hook. For fix this try to replace your condition in other place, for example in componentDidUpdate method .

componentDidUpdate() {
 if (this.state.loginError) {
    console.log('Error!') //does not work
    loginError(target);
    this.setState({ loginError: false });
   }
}

Check this: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_functio

You are basically trying to check the state when the error is still not caught, and hence the state has not changed.

If you move your code to the render method you will see that it will works since it will re-render after the state changes. Or you get the state change withing the componentDidUpdate method.

Why don't you try Promises instead, which is very clear and simple way around.

class LoginPage extends Component {
    constructor(props) {
        super(props);
        this.state = {
            navigate: false,
            loginError: false,
        }
    }

    handleSubmit = (e) => {
        e.preventDefault();
        return new Promise(resolve, reject){
        axios.post('http://localhost:3016/auth/login', userLogin, {withCredentials: true})
            .catch(err => {
                    reject(err);
            })
            .then(result => resolve(result));
        }

        //Else where in Your component use this promise, where ever you call it..

        handleSubmit().then(// success code).error(// error code)
    };

Because axios.post returns a promise, all code you'll write after it will be executed before the .then() or .catch() statements. If your need is to call loginError() function when the request fails you can call it in .catch statement :

axios.post('http://localhost:3016/auth/login', userLogin, {withCredentials: true})
    .catch(err => {
         loginError(target);
    });

If you need your function to be executed after updating the state you can use the setState callback (second argument) :

axios.post('http://localhost:3016/auth/login', userLogin, {withCredentials: true})
    .catch(err => {
         this.setState({ loginError: true }, () => { loginError(target); })
    });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM