【问题标题】:React Authentication Context being null initiallyReact Authentication Context 最初为空
【发布时间】:2020-09-16 14:39:45
【问题描述】:

我正在使用 React 上下文来保存我的应用程序的身份验证状态。目前,我遇到一个问题,每当我尝试点击/groups/:id 时,它总是先将我重定向到/login,然后再重定向到/UserDash。发生这种情况是因为我的 AuthProvider 的上下文更新速度不够快,而我的 Private Route 使用 AuthContext 来决定是否重定向。

<AuthProvider>
    <Router>
        <Switch>
            <LoggedRoute exact path = "/" component = {Home}/>
            <Route exact path = "/login" component = {Login}/>
            <PrivateRoute exact path = "/groups/:id" component = {GroupDash}/>
            <PrivateRoute exact path = "/UserDash" component = {UserDash}/>
        </Switch>
    </Router>
</AuthProvider>

在另一个文件中:

export const AuthContext = React.createContext();

export const AuthProvider = ({children}) => {
  const [currentUser, setCurrentUser] = useState(null);
  useEffect(() => {
      firebaseApp.auth().onAuthStateChanged(setCurrentUser);
  },[]);
    return (
        <AuthContext.Provider
            value = {{currentUser}}
        >
            {children}
        </AuthContext.Provider>
    );

我的私人路线:

const PrivateRoute = ({component: RouteComponent, ...rest}) => {
    const {currentUser} = useContext((context) => AuthContext);
    return (
        <Route
            {...rest}
            render={routeProps => (currentUser) ? (<RouteComponent{...routeProps}/>) : (<Redirect to={"/login"}/>)}
        />
    )
};

还有我的登录页面

 const {currentUser} = useContext(AuthContext);
    if (currentUser) {
        return <Redirect to = "/UserDash" />
    }
    return (
        <button onClick={(e) => {googleLogin(history)}}>Log In</button>
    );

有没有办法在私有路由将用户重定向到登录页面之前强制加载上下文?我尝试在我的 PrivateRoute 中使用 firebase.auth().currentUser,但这也失败了,我仍然被重定向到 "/login",然后被推送到 "/UserDash"

【问题讨论】:

    标签: reactjs firebase firebase-authentication react-router react-context


    【解决方案1】:

    由于 useEffect 在渲染之后运行,并且在 useEffect 中获取的值来自异步调用,因此可以做的是实际保持加载状态,直到数据可用为止

    export const AuthContext = React.createContext();
    
    export const AuthProvider = ({children}) => {
      const [currentUser, setCurrentUser] = useState(null);
      const [isLoading, setIsLoading] = useState(true);
      useEffect(() => {
          firebaseApp.auth().onAuthStateChanged((user) => {
              setCurrentUser(); setIsLoading(false)
          });
      },[]);
        return (
            <AuthContext.Provider
                value = {{currentUser, isLoading}}
            >
                {children}
            </AuthContext.Provider>
        );
      }
    

    然后在privateRoute中

    const PrivateRoute = ({component: RouteComponent, ...rest}) => {
        const {currentUser, isLoading} = useContext((context) => AuthContext);
        if(isLoading) return <div>Loading...</div>
        return (
            <Route
                {...rest}
                render={routeProps => (currentUser) ? (<RouteComponent{...routeProps}/>) : (<Redirect to={"/login"}/>)}
            />
        )
    };
    

    【讨论】:

    • 有没有办法在渲染发生之前运行异步调用,这样我可以减少加载时间?
    • 即使你最初运行它,因为它是一个异步调用,所以不能保证它会在你使用它之前解决。无论如何 useEffect 是写这个的正确地方。将来 react-suspense 可能会导致这种情况发生变化
    猜你喜欢
    • 2021-02-19
    • 1970-01-01
    • 2022-06-10
    • 2019-05-02
    • 1970-01-01
    • 2012-03-07
    • 2021-12-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多