受保护的路由无法与 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 && Component) return <Route><Component .../></Route>
等将有助于查明问题。
感谢您的帮助,我想我已经找到了解决方案
【参考方案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 一起正常工作的主要内容,如果未能解决你的问题,请参考以下文章