React身份验证上下文最初为空

时间:2020-05-29 04:54:41

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

我使用React上下文来保留我的应用程序的身份验证状态。目前,我遇到一个问题,即每次尝试按下/groups/:id时,它总是首先将我重定向到/login,然后再重定向到/UserDash。发生这种情况是因为AuthProvider的上下文更新速度不够快,并且我的私有路由利用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"

1 个答案:

答案 0 :(得分:2)

由于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"}/>)}
        />
    )
};