受保护的路由无法与 React 和 Firebase 一起正常工作

Posted

技术标签:

【中文标题】受保护的路由无法与 React 和 Firebase 一起正常工作【英文标题】:Protected route not working correctly with React and Firebase 【发布时间】:2021-02-03 18:25:58 【问题描述】:

我正在使用 firebase 和 react 构建一个小型应用程序,目前正在实施身份验证。我在我的应用程序组件中将 onAuthStateChanged 设置为副作用,每当用户登录时,它都应该从 ProtectedRoute 重定向到所需的组件。

这可以正常工作,但不幸的是,在刷新页面时,ProtectedRoute 没有呈现正确的组件,只是触发了重定向。

我知道发生了什么:刷新时用户是空的,然后才发生变化,所以我希望看到屏幕闪烁和正确的重定向。

您能否看看下面的代码并告诉我如何解决此问题?

应用组件:

const App = () => 
  const [authUser, setAuthUser] = useState<firebase.User | null>(null);
  const Firebase = useContext(FirebaseContext);

  useEffect(() => 
    const authListener = Firebase!.auth.onAuthStateChanged((authUser) => 
      authUser ? setAuthUser(authUser) : setAuthUser(null);
    );

    return () => authListener();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  , []);

  return (
    <AuthUserContext.Provider value=authUser>
      <Router>
        <div>
          <Navigation />

          <hr />

          <Route exact path=ROUTES.LANDING component=Landing />
          <Route exact path=ROUTES.SIGN_UP component=SignUpPage />
          <Route exact path=ROUTES.SIGN_IN component=SignIn />
          <Route
            exact
            path=ROUTES.PASSWORD_FORGET
            component=PasswordForget
          />
          <ProtectedRoute exact path=ROUTES.HOME component=Home />
          <ProtectedRoute exact path=ROUTES.ACCOUNT component=Account />
          <Route exact path=ROUTES.ACCOUNT component=Account />
          <Route exact path=ROUTES.ADMIN component=Admin />
        </div>
      </Router>
    </AuthUserContext.Provider>
  );
;

受保护的路线:

interface Props extends RouteProps 
  component?: any;
  children?: any;


const ProtectedRoute: React.FC<Props> = (
  component: Component,
  children,
  ...rest
) => 
  const authUser = useContext(AuthUserContext);

  return (
    <Route
      ...rest
      render=(routeProps) =>
        !!authUser ? (
          Component ? (
            <Component ...routeProps />
          ) : (
            children
          )
        ) : (
          <Redirect
            to=
              pathname: ROUTES.SIGN_IN,
              state:  from: routeProps.location ,
            
          />
        )
      
    />
  );
;

【问题讨论】:

不是解决方案,但是:我认为返回组件的***条件有时会产生奇怪的行为?我会尝试重写为简单返回的条件块。例如。 if(authUser &amp;&amp; Component) return &lt;Route&gt;&lt;Component .../&gt;&lt;/Route&gt; 等将有助于查明问题。 感谢您的帮助,我想我已经找到了解决方案 【参考方案1】:

找到了解决办法。必须添加检查用户身份验证状态的标志(该标志的默认值设置为 true)。 Flag 需要作为 prop 传递给 ProtectedRoute,如果是 True 则渲染一些加载组件:

应用组件:

const App = () => 
  const [authUser, setAuthUser] = useState(false);
  const [authPending, setAuthPending] = useState(true);
  const Firebase = useContext(FirebaseContext);

  useEffect(() => 
    const authListener = Firebase!.auth.onAuthStateChanged((authUser) => 
      setAuthUser(!!authUser);
      setAuthPending(false);
    );

    return () => authListener();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  , []);

  return (
    <AuthUserContext.Provider value=authUser>
      <Router>
        <div>
          <Navigation />

          <hr />
          <Switch>
            <Route exact path=ROUTES.LANDING component=Landing />
            <Route exact path=ROUTES.SIGN_UP component=SignUpPage />
            <Route exact path=ROUTES.SIGN_IN component=SignIn />
            <Route
              exact
              path=ROUTES.PASSWORD_FORGET
              component=PasswordForget
            />
            <ProtectedRoute
              pendingAuth=authPending
              exact
              path=ROUTES.HOME
              component=Home
            />
            <ProtectedRoute
              pendingAuth=authPending
              exact
              path=ROUTES.ACCOUNT
              component=Account
            />
            <Route exact path=ROUTES.ACCOUNT component=Account />
            <Route exact path=ROUTES.ADMIN component=Admin />
          </Switch>
        </div>
      </Router>
    </AuthUserContext.Provider>
  );
;

ProtectedRoute:

interface Props extends RouteProps 
  component?: any;
  children?: any;
  pendingAuth: boolean;


const ProtectedRoute: React.FC<Props> = (
  component: Component,
  children,
  pendingAuth,
  ...rest
) => 
  const authUser = useContext(AuthUserContext);

  if (pendingAuth) 
    return <div>Authenticating</div>;
  

  return (
    <Route
      ...rest
      render=(routeProps) =>
        !!authUser ? (
          Component ? (
            <Component ...routeProps />
          ) : (
            children
          )
        ) : (
          <Redirect
            to=
              pathname: ROUTES.SIGN_IN,
              state:  from: routeProps.location ,
            
          />
        )
      
    />
  );
;

【讨论】:

以上是关于受保护的路由无法与 React 和 Firebase 一起正常工作的主要内容,如果未能解决你的问题,请参考以下文章

React Redux with hooks - 身份验证和受保护的路由

React-router-dom 受保护的路由不起作用

React Router 受保护的路由

使用React构建受保护的路由

如何在 react redux 中添加受保护的路由

即使我在 react/redux 中使用受保护的路由设置了身份验证,我仍然会被注销?当我刷新页面时