React-Django应用登录用户状态持久化与受保护路由问题求助
解决React受保护路由初始用户状态为null导致的错误重定向问题
问题原因
当前AuthContext初始化时user默认设为null,而从localStorage读取用户数据的逻辑放在useEffect中——这个钩子是组件挂载后才执行的。所以App组件第一次渲染时,user还是null,触发了跳转到登录页的逻辑;等useEffect执行完更新用户状态时,重定向已经完成了。
解决方案一:初始化时直接读取localStorage
直接在初始化state时从localStorage获取用户数据,避免依赖useEffect的异步执行时机。
修改src/context/AuthContext.js:
export const AuthContext = createContext() export const authReducer = (state, action) => { switch (action.type){ case "LOGIN": return { user: action.payload } case "LOGOUT": localStorage.removeItem("mysUser") return { user: null } default: return state } } export const AuthContextProvider = ({ children }) =>{ // 初始化时直接读取localStorage const initialUser = JSON.parse(localStorage.getItem("mysUser")) || null; const [state, dispatch] = useReducer(authReducer, { user: initialUser }) // 保留useEffect处理后续可能的token验证等逻辑(可选) useEffect(() => { // 如果需要验证token有效性,可以在这里调用后端接口 // 比如: // if (initialUser) { // fetch('/api/validate-token', { // headers: { 'Authorization': `Bearer ${initialUser.token}` } // }) // .then(res => { // if (!res.ok) dispatch({ type: "LOGOUT" }) // }) // } }, []) console.log("AuthContext state: ", state) return ( <AuthContext.Provider value={{ ...state, dispatch}}> { children } </AuthContext.Provider> ) }
这样App组件第一次渲染时,user就已经是localStorage中的值(如果存在),不会触发错误重定向。
解决方案二:添加加载状态,避免过早重定向
如果需要后端验证token有效性(防止localStorage中的过期token被滥用),可以在AuthContext中添加loading状态,在验证完成前不做重定向判断。
修改AuthContext.js
export const AuthContext = createContext() export const authReducer = (state, action) => { switch (action.type){ case "LOGIN": return { ...state, user: action.payload, loading: false } case "LOGOUT": localStorage.removeItem("mysUser") return { ...state, user: null, loading: false } case "SET_LOADING": return { ...state, loading: action.payload } default: return state } } export const AuthContextProvider = ({ children }) =>{ const initialState = { user: JSON.parse(localStorage.getItem("mysUser")) || null, loading: true }; const [state, dispatch] = useReducer(authReducer, initialState) useEffect(() => { const validateUser = async () => { const user = state.user; if (!user) { dispatch({ type: "SET_LOADING", payload: false }); return; } // 调用Django后端的token验证接口 try { const res = await fetch('/api/verify-token', { headers: { 'Authorization': `Bearer ${user.token}`, 'Content-Type': 'application/json' } }); if (!res.ok) { throw new Error("Token无效"); } // 验证通过,保持用户状态 dispatch({ type: "LOGIN", payload: user }); } catch (err) { // 验证失败,清除用户状态 dispatch({ type: "LOGOUT" }); } }; validateUser(); }, []) console.log("AuthContext state: ", state) return ( <AuthContext.Provider value={{ ...state, dispatch}}> { children } </AuthContext.Provider> ) }
修改App.js中的受保护路由
function App() { const { user, loading } = useAuthContext() return ( <div className="App"> <BrowserRouter> <NavbarComponent/> <div> <Routes> {/* protected route */} <Route path="/about" element={ loading ? ( <div>加载中...</div> {/* 可以替换为自定义加载组件 */} ) : user ? ( <About /> ) : ( <Navigate to="/login" /> ) } exact /> {/* non-protected routes */} <Route path="/" element={<Home />} /> <Route path="/signup" element={<Signup />} exact /> <Route path="/login" element={<Login/>} exact /> </Routes> </div> <FooterComponent /> </BrowserRouter> </div> ); } export default App;
这种方式会在验证用户状态的过程中显示加载界面,避免因为初始user为null导致的错误重定向,同时保证只有有效的用户才能访问受保护路由。
内容的提问来源于stack exchange,提问作者dl_atl
相关产品推荐
相关产品推荐

