React路由保护问题:useSelector初始返回null导致误跳转至登录页
路由保护问题解决方案
问题核心:Redux初始状态中userData.user为null,useSelector会立即返回该值,导致AuthProvider直接跳转到登录页,无法等待用户登录状态初始化完成。
解决步骤
1. 在Redux状态中添加加载状态
修改用户状态的初始值,增加isLoading字段标识用户信息是否正在初始化:
// userSlice.js const initialState = { user: null, isLoading: true, // 初始为true,等待登录状态校验 };
2. 添加初始化用户状态的异步逻辑
创建异步Thunk,在应用启动时从本地存储(如localStorage)校验登录状态并更新Redux:
// userSlice.js import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'; export const initializeUser = createAsyncThunk( 'user/initialize', async () => { const token = localStorage.getItem('authToken'); if (token) { // 调用后端接口获取用户信息 const res = await fetch('/api/auth/user', { headers: { Authorization: `Bearer ${token}` } }); return res.ok ? await res.json() : null; } return null; } ); const userSlice = createSlice({ name: 'userData', initialState, reducers: { // 其他用户操作reducer }, extraReducers: (builder) => { builder .addCase(initializeUser.pending, (state) => { state.isLoading = true; }) .addCase(initializeUser.fulfilled, (state, action) => { state.user = action.payload; state.isLoading = false; }) .addCase(initializeUser.rejected, (state) => { state.isLoading = false; }); } }); export default userSlice.reducer;
3. 修改AuthProvider逻辑
等待加载状态完成后再判断用户是否登录,避免初始null值导致的错误跳转:
// auth provider import React from "react"; import { useSelector } from "react-redux"; import { Navigate, useLocation } from "react-router-dom"; export const AuthContext = React.createContext(); export const AuthProvider = ({ children }) => { const { user: currentUser, isLoading } = useSelector((state) => state.userData); const location = useLocation(); // 加载中时显示过渡UI,可替换为自定义加载组件 if (isLoading) { return <div>加载中...</div>; } // 加载完成后,无用户则跳转登录页 if (!currentUser) { return ( <Navigate to="/signIn" replace state={{ path: location.pathname }} /> ); } return ( <AuthContext.Provider value={currentUser}>{children}</AuthContext.Provider> ); };
4. 在应用启动时触发初始化逻辑
在App组件中调用初始化Thunk,确保应用启动时校验登录状态:
// app.jsx import { useEffect } from 'react'; import { useDispatch } from 'react-redux'; import { initializeUser } from './path/to/userSlice'; function App() { const dispatch = useDispatch(); useEffect(() => { dispatch(initializeUser()); }, [dispatch]); return ( <div className="App grid"> <AuthProvider> <Navbar /> <Routes> <Route path="channels" element={<UserChannels />} /> <Route path="/channel/new" element={<CreateChannel />} /> <Route path="/channel/:channelID" element={<Channel />} /> </Routes> </AuthProvider> </div> ); }
原理说明
通过添加isLoading状态,我们避免了组件挂载时直接使用Redux初始的null值判断登录状态,而是等待登录状态校验完成后再做路由跳转决策,确保已登录用户能正常访问受保护路由。
内容的提问来源于stack exchange,提问作者Peter Austin
相关产品推荐
相关产品推荐

