React setState () does not update state after request $ .ajax ()

I use a reaction with a jet router. After authenticating with the onEnter Asynchronous hook on the IndexRoute, the application component gets rendered. The application component has an initial auth state that is set to undefined when it is displayed. auth status is passed to the Navbar component as prop, where it will be used to determine whether to show login, registration and logout.

When the application component is rendering, it componentDidMount()calls an ajax call to check again whether the user is authenticated. In response, he makes changes to the state. After changing the state from the ajax request, I register the state in the console, the this.setState()method does not change the state, but somehow calls the componentWillReceiveProps () method for the Navbar component and the value this.props.authis still undefined.

// Checks Authentication Asynchronously 
isAuthenticated(nextState, replace, callback) {
    $.ajax({
        type : 'GET',
        url : '/auth',
        success : function(res){
            if(!res){
                callback(replace({ pathname: '/login', query: { auth: 'false' } }));
            }else{
                callback();
            }
        }
    });
};

// routes
var routes = (
    <Router history={browserHistory}>
        <Route path="/" component={require('./components/app')}>
            <IndexRoute component={require('./components/dashboard/index')} onEnter={Auth.isAuthenticated}/>

            <Route path="/register"
                   component={require('./components/authentication/register')}
                   onEnter={Auth.isNotAuthenticated} />

            <Route path="/login"
                   component={require('./components/authentication/login')}
                   onEnter={Auth.isNotAuthenticated}/>

            <Route path="*"
                   component={require('./components/404/404')}/>
        </Route>
    </Router>
);

// App
const App = React.createClass({

    getInitialState(){
        return {
            auth : undefined
        }
    },

    componentDidMount(){
        console.log('App componentDidMount');
        this.checkAuth();
    },

    checkAuth(){
        var self = this;
        $.ajax({
            type : 'GET',
            url : '/auth',
            success : function(res){
                if(res){
                    self.setState({
                        auth : true
                    });
                }else{
                    self.setState({ auth : false});
                }
            }
        });
        console.log(this.state.auth);
    },

    render() {
        return(
            <div className="appWrapper">
                <Navbar auth={this.state.auth}/>

                <div className="container">
                    {this.props.children}
                </div>
            </div>
        );
    }
});

// Navbar
var Navbar = React.createClass({

    getInitialState(){
        return{
            user_actions : '' ,
            auth : this.props.auth
        }
    },

    componentDidMount(){
        console.log('Navbar componentDidMount ', this.props.auth);
        this.checkAuthState();
    },

    componentWillReceiveProps(){
        console.log('Navbar componentWillReceiveProps ', this.props.auth);
        this.setState({
            auth : this.props.auth
        });
        this.checkAuthState();
    },

    checkAuthState(){
        console.log('Nav Mounted with auth : ', this.state.auth);

        if(this.state.auth == undefined){
            this.state.user_actions = '';
        }
        if(!this.state.auth){
            this.state.user_actions =   <ul className="nav navbar-nav navbar-right">
                <li><a href="/login">Login</a></li>
                <li><a href="/register">Register</a></li>
            </ul>;
            this.setState({
                user_actions : this.state.user_actions
            });
        }

        if(this.state.auth){
            this.state.user_actions =   <ul className="nav navbar-nav navbar-right">
                <li><a href="/logout">Logout</a></li>
            </ul>;
            this.setState({
                user_actions : this.state.user_actions
            });
        }
    },

    render : function(){
        return (
            <nav className="navbar navbar-default">
                <div className="container">
                    <a href="/" className="navbar-brand">Reactor</a>
                    {this.state.user_actions}
                </div>
            </nav>
        );
    }
});
+6
source share
4 answers

First of all, I suggest you re-read the React.JS documentation, because there are a few things to note:

  • Do not touch this.statedirectly, use the method setState.(line: 108, 111, 121, 133, 136, 146)
  • , , . (line: 111, 121, 136, 146)

; ; :

1. Ajax , .

, ajax! , :

Ajax . JS console.log , , ajax-. :

$.ajax({ ...,
    success: function(res) {
        if(res) { self.setState({ auth : true }); }/
        ...
    }  // will executed later (after ajax get response)
 });
 console.log(this.state.auth); // will executed first, this is why it always prints the value as undefined

-, . , , this.state.auth false:

this.setState({ auth: true});
console.log(this.state.auth); // will print false, instead of true as your new value 

componentWillUpdate(nextProps, nextState). : React.JS

2. componentWillReceiveProps() Navbar, this.props.auth undefined.

, setState() ajax. Navbar, , App ( auth), componentWillReceiveProps().

, :

// App
const App = React.createClass({
    getInitialState : function(){
        return {
            auth : false
        }
    },

    componentDidMount : function() {
        console.log('App componentDidMount');
        this.checkAuth();
    },

    componentWillUpdate : function(nextProps, nextState) {
        //you'll see the changing state value in here
        console.log('Your prev auth state: ' + this.state.auth);
        console.log('Your next auth state: ' + nextState.auth);
    },

    checkAuth : function(){
        var self = this;
        $.ajax({
            type : 'GET',
            url : '/auth',
            success : function(res){
                if(res){
                    self.setState({ auth : true });
                }
            }
        });
    },

    render : function(){
        return(
            <div className="appWrapper">
                <Navbar auth={this.state.auth}/>
                <div className="container">
                    {this.props.children}
                </div>
            </div>
        );
    }
});

// Navbar
// Because the navbar component receive data (this.props.auth) from parent (app) via props, so we're no longer need to assign auth as a state in Navbar component. 
const Navbar = React.createClass({
    render : function(){
        // you're no longer need checkAuthState method
        let navItems;
        if(!this.props.auth){
            navItems =  (<ul className="nav navbar-nav navbar-right">
                <li><a href="/login">Login</a></li>
                <li><a href="/register">Register</a></li>
            </ul>);
        } else {
            navItems =  (<ul className="nav navbar-nav navbar-right">
                <li><a href="/logout">Logout</a></li>
            </ul>);
        }

        return (
            <nav className="navbar navbar-default">
                <div className="container">
                    <a href="/" className="navbar-brand">Reactor</a>
                    { navItems }
                </div>
            </nav>
        );
    }
});

, !

+21

ajax. . ajax success, . .

var reactModule = React.createClass({
   getInitialState:function(){

    },
  render: function() {
    return (      
           <div>
            content
          </div>
    );
  },
componentDidMount: function() {
     var ajaxSuccess=this.ajaxSuccess;

               $.ajax({
                   type: "POST",
                   url: $api_url + 'index.php/app/icon1_update',
                   dataType: "text",
                   data:fd,
                   contentType: false,
                   processData: false,
                   success: ajaxSuccess
               });  
     }, 
ajaxSuccess:function(e){
   //e is the result. update state here.
}  
});
+1

, : W/E:

componentWillReceiveProps(
  object nextProps
)

https://facebook.imtqy.com/react/docs/component-specs.html#updating-componentwillreceiveprops

, "nextProps". .

: checkAuthState() , componentDidMount, setState.

0
source

Just use the arrow functions to access this:

success: () => {
this.setState({ data: value })
}
0
source

All Articles