reactjs - 当页面重新加载时,firebase.auth.currentUser 返回 null
问题描述
我正在尝试通过 react 对我的网络应用程序实施 firebase 身份验证。
登录/注销流程是这样的。
在 SIGN-IN 页面成功登录的用户,被重定向到 HOME 页面。
当非认证用户访问 HOME 页面时,重定向到 SIGN-IN 页面
确认用户从SIGN-IN被重定向到HOME页面,并且在HOME页面点击“sign out”按钮的用户被重定向到SIGN-IN页面。
但是,问题是当经过身份验证的用户在主页重新加载页面时,用户被重定向到 SIGN-IN 页面,然后被重定向到 HOME 页面。
我认为经过身份验证的用户不会被重定向到登录页面。
我该如何解决这个问题?
我的代码如下:
- FirebaseContext.tsx
import * as React from "react";
import { createContext, useContext } from "react";
import { firebase } from "../utils";
const FirebaseContext = createContext(firebase);
export const FirebaseProvider: React.FC = props => (
<FirebaseContext.Provider value={firebase}>
{props.children}
</FirebaseContext.Provider>
);
export const useFirebase = () => useContext(FirebaseContext);
- 应用程序.tsx
import * as React from "react";
import { Route, Switch } from "react-router-dom";
import * as routes from "./constants/routes";
import { FirebaseProvider } from "./contexts/FirebaseContext";
import { Home } from "./pages/Home";
import { SignIn } from "./pages/SignIn";
const App: React.FC = () => {
return (
<FirebaseProvider>
<Switch>
<Route exact={true} path={routes.SIGN_IN} component={SignIn} />
<Route exact={true} path={routes.HOME} component={Home} />
</Switch>
</FirebaseProvider>
);
};
export default App;
- AuthUserHook.ts
import { useState, useEffect } from "react";
import { User } from "firebase";
export const useAuthUser = (firebase: any) => {
const [authUser, setAuthUser] = useState<User | null>(firebase.auth.currentUser);
useEffect(() => {
const unsubcribe = firebase.auth.onAuthStateChanged((user: User | null) => setAuthUser(user));
unsubcribe();
}, []);
return authUser;
};
- 登录.tsx
import * as React from "react";
import { useHistory } from "react-router-dom";
import { useFirebase } from "../../contexts/FirebaseContext";
import { useAuthUser } from "../../Hooks/AuthUserHook";
import * as routes from "../../constants/routes";
import { SignInForm } from "./SignInForm";
export const SignIn: React.FC = () => {
const firebase = useFirebase();
const authUser = useAuthUser(firebase);
const history = useHistory();
if (authUser) {
history.push(routes.HOME);
}
return (
<div>
<h1>Sign in</h1>
<SignInForm />
</div>
);
};
- 主页.tsx
import * as React from "react";
import { useHistory } from "react-router-dom";
import { useFirebase } from "../../contexts/FirebaseContext";
import { useAuthUser } from "../../Hooks/AuthUserHook";
import * as routes from "../../constants/routes";
export const Home: React.FC = () => {
const firebase = useFirebase();
const authUser = useAuthUser(firebase);
const history = useHistory();
if (!authUser) {
history.push(routes.SIGN_IN);
}
return (
<div>
<h2>Home Page</h2>
<p>The Home Page is accessible by every signed in user.</p>
</div>
);
};
解决方案
页面加载后,Firebase SDK 会尝试从本地存储恢复用户的凭据。作为其中的一部分,它会与服务器检查用户的登录会话是否仍然有效,并且在此期间 currentUser 为空。然后,一旦登录会话恢复,它就会触发一个onAuthStateChanged
具有新状态的事件。所以你需要挂钩来更新你的状态。
我通常处理这个问题的方法是从“登录”屏幕开始,然后当您在身份验证状态更改处理程序中获得有效用户时重定向到主屏幕。
一个额外的技巧是在用户之前进行身份验证时将您自己的标志存储在本地存储中,然后在页面加载时读取它。由于对该本地存储的访问是同步的,这意味着您可以在他们之前登录的情况下立即显示主屏幕。请记住,您的本地标志可能是错误的(因为这正是 Firebase 必须与服务器检查的原因),因此您应该能够处理导航回登录屏幕。
推荐阅读
- php - 我应该如何根据特定价格更改单元格颜色?
- c - 根据加速度计和陀螺仪值计算的当前角度偏移新角度
- pandas - 如何根据 datediff 为一天的日期合并两个数据框?
- javascript - 在 express res.send() 中合并各种后端请求
- django - Ajax: SyntaxError: Unexpected token < in JSON at position 2
- r - 忽略导入中存在解析错误的文件 (read_csv)
- scylla - scylla compile 过程中遇到的问题
- java - 点击按钮不允许添加点击次数
- firebase - 如何使用 HTTP 请求将嵌套数据发布到 firebase firestore?
- php - WooCommerce 订阅 - 根据变体 ID 更改新订阅的下一个账单日期