简体   繁体   English

受保护的路由在 React 和 Firebase 中无法正常工作

[英]Protected route not working correctly with React and Firebase

I'm building a small app with firebase and react and currently working on implementing the authentication.我正在构建一个带有 firebase 和 react 的小应用程序,目前正在实施身份验证。 I've set the onAuthStateChanged in my app component as a side effect and whenever user is logged in it should be redirected to a desired component from ProtectedRoute.我在我的应用程序组件中设置了 onAuthStateChanged 作为副作用,每当用户登录时,它应该从 ProtectedRoute 重定向到所需的组件。

This works correctly but unfortunately when refreshing the page the ProtectedRoute is not rendering correct component and is just firing redirection.这可以正常工作,但不幸的是,在刷新页面时 ProtectedRoute 未呈现正确的组件,而只是触发重定向。

I get what is happening: on refresh user is empty and only after then it change so I would expect to see a screen flicker and a proper redirection.我明白发生了什么:刷新时用户为空,只有在此之后它才会改变,所以我希望看到屏幕闪烁和正确的重定向。

Could you please look at below code and maybe tell me how to fix this behavior?你能不能看看下面的代码,也许告诉我如何解决这个问题?

App component:应用组件:

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>
  );
};

Protected Route:保护路线:

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 },
            }}
          />
        )
      }
    />
  );
};

Found the fix.找到了修复。 Had to add the flag checking for user authentication status (default value of that flag is set to true).必须添加检查用户身份验证状态的标志(该标志的默认值设置为 true)。 Flag needs to be passed to ProtectedRoute as prop and if is True then render some loading component: Flag 需要作为 prop 传递给 ProtectedRoute,如果为 True 则渲染一些加载组件:

App component:应用组件:

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 },
            }}
          />
        )
      }
    />
  );
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM