首页 文章

React React-Router:在重定向时替换子组件时重新渲染Navbar组件

提问于
浏览
2

我正在使用React 15.0.1和react-router 2.2.1 . 我正在使用App作为父组件,它呈现从路由器处理程序传递的子组件 .

var App = React.createClass({

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

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

    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(){
        this.checkAuth();
    },

    componentWillReceiveProps(nextProps){
        this.setState({
            auth : nextProps.auth
        }, function(){
            this.checkAuthState();
        });

        console.log(nextProps.auth);
    },

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

    checkAuthState(){

        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>
        );
    }
});

这些是我的路线处理程序 . 当用户登陆路线时,将检查他们的身份验证 . 如果验证失败,它们将被重定向到登录路由 .

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>
);

当应用程序组件首次使用Navbar和子组件安装时,它会检查身份验证并相应地添加指向导航栏的链接 . 当用户在成功登录后从登录路由重定向到索引路由时,子组件将替换为其他组件,并且会调用该组件的生命周期方法,但Navbar不会重新渲染 . 如何重新渲染Navbar组件,以便它可以再次检查身份验证并更改为导航栏链接?

2 回答

  • 2

    我想通了,我从App组件传递了一个方法到子组件 .

    var App = React.createClass({
    
        getInitialState(){
            return {
                auth : false
            }
        },
    
        checkAuth(){
            var self = this;
            $.ajax({
                type : 'GET',
                url : '/auth',
                success : function(res){
                    if(res){
                        self.setState({
                            auth : true
                        });
                    }else{
                        self.setState({ auth : false});
                    }
                }
            });
        },
    
        updateNavbar(){
            this.checkAuth();
        },
    
        render() {
            return(
                <div className="appWrapper">
                    <Navbar auth={this.state.auth}/>
                    <div className="container">
                        {React.cloneElement(this.props.children, {update: this.updateNavbar})}
                    </div>
                </div>
            );
        }
    });
    

    当子组件,例如Login验证用户时,它调用作为prop传递的更新方法,将重新检查身份验证,并更改为App组件auth状态,这将触发Navbar组件上的componentWillReceiveProps方法,其中包含将更改状态和重新渲染Navbar组件 . 这就是我想要实现的目标 .

    var Login    =   React.createClass({
        getInitialState(){
            return {
                user : {email  : '', password : ''},
                auth_redirect : '',
                errors  : {},
                message : ''
            }
        },
    
        componentWillMount(){...},
    
        registerFormIsValid : function(){....},
    
        validateUser : function(){
            var self = this;
            $.ajax({
                type : 'POST',
                url : '/login',
                data : {
                    email : this.state.user.email,
                    password : this.state.user.password
                },
                success : function(res){
                    if(!res.auth){
                        self.setState({
                            message : <Alert message="Invalid Email or Password!"/>
                        });
                    }else{
                        self.props.update(); // Update Navbar 
                        self.context.router.push('/');
                    }
                }
            });
        },
    
        Authenticate : function(event){....},
    
        saveUserState : function(event){...},
    
        render : function(){
            return (
                <div>
                    <div className="login container">
                        <LoginForm
                            user={this.state.user}
                            onChange={this.saveUserState}
                            onSave={this.Authenticate}
                            errors={this.state.errors} />
                        {this.state.message}
                    </div>
                </div>
            );
        }
    });
    

    现在我可以通过调用 this.props.update() 从路由处理程序传递的任何子组件更新我的Navbar组件链接 .

  • 0

    您需要在单独的服务中抽象auth逻辑,例如

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

    然后在你 App 组件中你可以做到

    updateAuth(isLoggedIn) {
      self.setState({auth: isLoggedIn});
    }
    
    componentWillMount() {
      auth.onChange = this.updateAuth;
    }
    

    并且在您需要检查身份验证的每个路由中添加 onEnter={auth.check} 或者您可以将数据存储在localstorage中以避免每次都调用api .

    basic example of auth flow with react-router

相关问题