React-Router v6路由传递State为null问题求助
问题原因与解决方案
核心问题
你在Link组件的state中传递了setToken函数,而react-router的state仅支持可序列化数据(字符串、数字、普通对象等),函数无法被序列化,这会导致整个state传递失败,最终useLocation()获取到的state为null。
另外,直接通过手动输入URL、刷新页面访问路由时,state也会丢失(因为state存储在内存中,并非URL的一部分),这也是常见的state为null的场景。
解决方案:用Context API全局共享状态
既然需要在多个页面组件中共享token和setToken,直接通过Link传state不是最优方案,推荐使用React Context API实现全局状态共享:
1. 创建AuthContext文件
新建AuthContext.js:
import { createContext, useContext, useState } from 'react'; const AuthContext = createContext(); export function AuthProvider({ children }) { const [token, setToken] = useState(false); return ( <AuthContext.Provider value={{ token, setToken }}> {children} </AuthContext.Provider> ); } export function useAuth() { return useContext(AuthContext); }
2. 修改App.js,用AuthProvider包裹路由
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom'; import { AuthProvider } from './AuthContext'; import SearchPage from './pages/Search.page'; import HomePage from './pages/Home.page'; import ProfilePage from './pages/Profile.page'; import AddEntryPage from './pages/AddEntry.page'; import LoginPage from "./pages/Login.page"; import CreateUserPage from "./pages/CreateUser.page"; import './App.css'; function App() { return ( <AuthProvider> <Router> <div> <nav> <ul> <li> <Link to='/profile'>Profile</Link> </li> <li className='right-edge-pusher'> <Link to='/'>Home</Link> </li> <li> <Link to='/add'>Add</Link> </li> <li> <Link to='/search'>Search</Link> </li> </ul> </nav> <Routes> <Route path='/' element={<HomePage /> }/> <Route path='/profile' element={<ProfilePage />}/> <Route path='/add' element={<AddEntryPage />}/> <Route path='/search' element={<SearchPage />}/> <Route path="/login" element={<LoginPage /> }/> <Route path="/user" element={<CreateUserPage /> }/> </Routes> </div> </Router> </AuthProvider> ); } export default App;
3. 修改ProfilePage.js,通过useAuth获取状态
import { useState } from "react"; import { useQuery } from "react-query"; import { Link } from 'react-router-dom'; import { useAuth } from '../AuthContext'; import axios from 'axios'; import PostSnippet from '../components/PostSnippet'; function ProfilePage() { const { token, setToken } = useAuth(); console.log(token); const [enabled, setEnabled] = useState(false); const fetchProfile = () => { return axios.get("http://localhost:5000/saved") } const { data, isError, error, isLoading } = useQuery('profile', fetchProfile, { enabled }); return ( <div> { !token && <> <Link to={'/login'}>Login</Link> <br/> <br/> <Link to={'/user'}>Create User</Link> </> } { isLoading && <h2>Loading...</h2> } { isError && <h2>{error.response.data.message.message}</h2> } { data && data.data.map(item => { return ( <PostSnippet key={item.id} plantName={item.name} plantTempRange={`${item.sow_temp_range}f`} plantZone={item.planting_zone} plantSunReq={`${item.sun_req} sun`} plantDescription='To be added...' /> ); }) } </div> ); } export default ProfilePage;
额外注意事项
- 如果必须使用
Link传state,确保只传递可序列化数据,不要包含函数、Symbol等不可序列化类型。 - 刷新页面或手动输入URL时,
state会丢失,这种场景下可以给state设置默认值,或者将关键状态存储在localStorage/sessionStorage中,组件初始化时从本地存储恢复。
内容的提问来源于stack exchange,提问作者Jewel
相关产品推荐
相关产品推荐

