React+react-router+Firebase项目刷新页面跳转登录页问题解决
问题根因
- 初始状态时序问题:Redux 中
currentUser初始值为null,页面刷新后 Firebase 身份校验是异步执行的,在 auth 状态返回前,权限校验钩子就已经触发,识别到currentUser为空直接跳转登录页。 - 用户数据覆盖bug:App.js 中 auth 监听逻辑错误,你在已登录分支设置完带 Firestore 扩展字段(如 roles)的用户信息后,外部还执行了一次
setCurrentUser(userAuth),会把带 roles 的完整用户对象覆盖为 Firebase 原生的 auth 对象,原生对象没有存储在 Firestore 里的 roles 字段,导致管理员身份校验永远失败,刷新后停留在登录页。
修复步骤
1. 修复App.js的auth监听逻辑
把全局的 setCurrentUser(userAuth) 移到未登录的 else 分支,避免覆盖带扩展字段的用户信息:
useEffect(() => { const authListener = auth.onAuthStateChanged(async (userAuth) => { if (userAuth) { const userRef = await handleUserProfile(userAuth); userRef.onSnapshot((snapshot) => { setCurrentUser({ id: snapshot.id, ...snapshot.data(), }); }); } else { // 仅未登录时设置用户为null setCurrentUser(userAuth); } }); return () => { authListener(); }; }, []);
2. 新增auth加载状态,避免未完成校验时触发跳转
修改userReducer,新增加载状态标记:
const INITIAL_STATE = { currentUser: null, authLoading: true, // 标记身份校验是否完成 }; const userReducer = (state = INITIAL_STATE, action) => { switch (action.type) { case userTypes.SET_CURRENT_USER: return { ...state, currentUser: action.payload, authLoading: false, // 身份校验完成,关闭加载态 }; default: return state; } };
3. 修改权限校验钩子,加载状态下不执行跳转
修改useAuth:
const mapState = ({ user }) => ({ currentUser: user.currentUser, authLoading: user.authLoading, }); const useAuth = (props) => { const { currentUser, authLoading } = useSelector(mapState); useEffect(() => { if (authLoading) return; // 校验中不跳转 if (!currentUser) { props.history.push("/login"); } }, [currentUser, authLoading]); return !authLoading && currentUser; };
修改useAdmin:
const mapState = ({ user }) => ({ currentUser: user.currentUser, authLoading: user.authLoading, }); const useAdmin = (props) => { const { currentUser, authLoading } = useSelector(mapState); const history = useHistory(); useEffect(() => { if (authLoading) return; // 校验中不跳转 if (!checkUserAdmin(currentUser)) { history.push("/login"); } }, [currentUser, authLoading]); return !authLoading && checkUserAdmin(currentUser); };
4. 可选优化:增加全局加载态避免页面闪烁
修改App.js的mapStateToProps引入加载状态,校验完成前渲染加载占位符:
const mapStateToProps = ({ user }) => ({ currentUser: user.currentUser, authLoading: user.authLoading, }); const App = (props) => { const { setCurrentUser, currentUser, authLoading } = props; // 校验未完成时显示加载 if (authLoading) return <div>加载中...</div> // 原有return逻辑不变 ... }
内容的提问来源于stack exchange,提问作者JS3
相关产品推荐
相关产品推荐

