这个 React Private Route 没有及时捕获 Firebase Auth?

This React Private Route isn't catching Firebase Auth in time?

我正在使用 React 为网站构建管理面板,并使用 Firebase 作为身份验证系统(和数据存储等)。

我试过几个专用路由版本,但最终选择了似乎最适合 Firebase 的版本。但是,有一个小问题。它在用户登录时运行良好,根据 Firebase Auth 文档,默认情况下,它应该缓存用户。

但是,如果我登录,然后关闭选项卡并在新选项卡中重新打开它,我将被弹出回到登录页面(如果用户未登录则应该如此)。

我是 运行 通过节点在本地主机上的站点,但这可能无关紧要。 console.log 报告用户实际上已登录,但无论如何都会被踢回来。一切都封装在 useEffect 中,它监视 LoggedIn 值,并检查 Auth 状态。

有什么方法可以防止登录用户在重新打开标签页时被踢出吗?

  import { FunctionComponent, useState, useEffect } from 'react';
  import { Route, Redirect } from 'react-router-dom';
  import { getAuth, onAuthStateChanged } from 'firebase/auth';
  import Routes from '../../helpers/constants';

  export const PrivateRoute: FunctionComponent<any> = ({  
      component: Component,  
      ...rest  
      }) => {  
      const [LoggedIn, SetLoggedIn] = useState(false);

  // Check if the User is still authenticated first //
  useEffect(() => {
    const auth = getAuth();
    onAuthStateChanged(auth, (user:any) => {
      if (user.uid !== null)
      {
        SetLoggedIn(true);
        // This gets reached after the tab is re-opened, indicating it's cached.
        console.log("Logged In");
      }
    });
  }, [LoggedIn]);
  // On tab reload however, this acts as if LoggedIn is set to false after the cache check
  return (  
    <Route  
      {...rest}  
      render={(props:any) => {
          console.log(LoggedIn);
          return LoggedIn ? (  
              <Component {...props} />  
          ) : (  
              <Redirect to={Routes.LOGIN} />  
          );  
      }}  
  />  
  );  
};

它重定向是因为在您的私有路由的第一次呈现中,将 LoggedIn 状态设置为 true 的代码尚未执行。您可以使用额外的布尔状态来避免在您尚未检查身份验证状态时呈现路由。

  ...
  const [LoggedIn, SetLoggedIn] = useState(false);
  const [loading, setLoading] = useState(true);
  ...
      if (user.uid !== null) {
        setLoading(false);
        SetLoggedIn(true);
      }
  ...
  // On tab reload however, this acts as if LoggedIn is set to false after the cache check
  if(loading) return <div>Loading...</div>; // or whatever UI you use to show a loader

  return (
    <Route
      ...
    />
  );
};

您只需要在组件挂载上检查用户,您可以在 useEffect 挂钩中有一个空的依赖数组,并在挂钩清理中停止监听更新

  useEffect(() => {
    const auth = getAuth();
    const unsubscribe = onAuthStateChanged(auth, (user:any) => {
      ...
    });
    return unsubscribe; // stop listening when unmount
  }, []);

但是你会稍微重新发明轮子,已经有一个钩子可以使用 https://github.com/CSFrequency/react-firebase-hooks/tree/master/auth#useauthstate