React Router条件路由组件闪烁/闪烁

时间:2020-05-31 20:26:19

标签: javascript reactjs react-redux react-router

我仅在用户登录后才尝试渲染某些组件。用户是否登录由存储在redux存储中的当前用户对象确定。问题在于,包含路线的主App组件在其“第一次渲染”调用之前没有立即收到其props的当前用户对象。因此,它将重定向到“登录”页面。一两秒钟后,主要的App组件最终将对象接收到其props中,并重定向到了应该放置的位置。

我尝试将条件移至实际组件的render方法中,但该组件在“首次渲染”之前仍未从redux存储接收作为道具的用户对象,导致登录页面具有相同的“刷新”

class App extends React.Component {
    constructor() {
        super();
    }

    unsubscribeFromAuth = null;

    async componentDidMount(): void {
        this.unsubscribeFromAuth = await auth.onAuthStateChanged(async userAuth => {
            if (userAuth) {
                await this.props.setCurrentUser(userAuth);
            }
        })
    }

    componentWillUnmount(): void {
        this.unsubscribeFromAuth();
    }

    render() {
        return (
            <div>
                <Navbar />
                <BrowserRouter history={history}>
                    <div>
                    <Switch>
                        <Route exact={true} path={'/register'} render={() => this.props.currentUser
                                                                            ? <Profile/>
                                                                            : <Register/>}/>
                        <Route exact={true} path={'/profile'} render={() => this.props.currentUser
                            ? <Profile/>
                            : <Login/>}/>
                        <Route exact={true} path={'/login'} render={() => this.props.currentUser
                                                                        ? <Events/>
                                                                        : <Login/>}/>
                        <Route exact={true} path={'/events'} render={() => this.props.currentUser
                                                                         ? <Events/> : <Login/>}/>
                        <Route exact={true} path={'/my_events'} render={() => this.props.currentUser
                                                                            ? <MyEvents/> : <Login/>}/>
                        <Route exact={true} path={'/new_event'} render={() => this.props.currentUser
                                                                            ? <NewEvent/> : <Login/>}/>
                        <Route exact={true} path={'/edit_event'} render={() => this.props.currentUser
                                                                        ? <EventEdit/>
                                                                        : <Login/>}/>
                        <Route exact={true} path={'/apply-to-event'} render={() => this.props.currentUser
                                                                                 ? <ApplyToEvent/>
                                                                                 : <Login/>}/>
                        <Route path={'/'} render={() => this.props.currentUser
                            ? <Events/>
                            : <Login/>}/>
                    </Switch>
                    </div>
                </BrowserRouter>
            </div>
        );
    }
}

const mapStateToProps = ({ user }) => ({
    currentUser: user.currentUser
});

const mapDispatchToProps = (dispatch) => ({
    setCurrentUser: async user => await dispatch(setCurrentUser(user))
});

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(App);

我想找到一种方法来呈现组件,而又不会使Login组件闪烁/闪烁。

1 个答案:

答案 0 :(得分:2)

如果我正确理解了您的代码,似乎是问题不是路由器代码,而是redux身份验证状态的逻辑。

首先; componentDidMount始终在首次渲染后工作。因此,您永远无法在componentDidMount中实现所需的功能。您将永远错过第一个渲染。它会记住auth状态,而无需获取服务器即可知道它。

如果您想在首次渲染期间了解身份验证信息,则应使用localStorage或asyncStorage(forReact Native)。这样您就可以在第一次渲染时就知道了。

如果您坚持不使用localStorage;在更新身份验证状态之前,您可能会显示一些加载屏幕。因此,React路由器将没有机会路由到登录页面并返回。