React Router v6私有嵌套路由传递State及session状态丢失问题咨询
问题修复方案
问题根源
你当前的问题是沿用了React Router v5的私有路由实现逻辑,不符合v6的嵌套路由规则,同时没有正确传递路由上下文和状态,导致信息丢失:
- 原有私有路由返回布局组件时没有正确承接路由上下文,子路由无法拿到上层路由的location等信息
- 跳转登录时仅传递了路径名,丢失了原请求的查询参数、state等完整信息
- 未使用v6提供的
Outlet上下文能力传递私有路由状态给子路由
修复步骤
1. 重构私有路由组件
修改Routes.js中的Private组件,适配v6的路由逻辑,完整保留跳转前的所有路由信息:
const Private = ({ children }) => { const [state] = React.useContext(UserContext); const location = useLocation(); console.log(location) // 此处现在可以正常拿到完整的location,包括state、search查询参数 if (state.auth){ console.log('Authenticated'); return children; } else { console.log('Not Authenticated') // 跳转登录时将完整的原路由信息存在state中,避免信息丢失 return <Navigate to="/login" state={{ from: location }} replace /> } };
2. 修改路由配置
调整app路径的配置方式,将布局组件作为Private的子元素传入:
const routes = [ { path: 'app', element: ( <Private> <DashboardLayout /> </Private> ), children: [ // 原有子路由全部保留无需修改 { path: 'account', children: [ { path: 'integrations', element: <Integrations /> }, ] }, { path: 'dashboard', element: <Dashboard /> }, { path: 'audiences', element: <Audiences /> }, { path: 'creatives', element: <Creatives /> }, { path: 'copywriting', element: <Copywriting /> }, { path: 'settings', element: <ProjectSettings /> }, { path: 'user_settings', element: <UserSettings /> }, { path: 'fb_interests', element: <FbInterestsExplorer /> }, { path: '*', element: <NotFound /> }, ] }, // 剩余的根路径路由配置保持原有内容不变 { path: '/', element: <MainLayout />, children: [ { path: 'login', element: <Login /> }, { path: 'user/activate/:user_id', element: <UserConfirmation /> }, { path: '/', element: <Navigate to="/app/dashboard" /> }, { path: '*', element: <NotFound /> } ] } ];
3. 传递状态给子路由
如果需要将私有路由中的用户状态、路由信息传递给所有子路由,可以通过Outlet的上下文能力实现,修改DashboardLayout.js:
const DashboardLayout = () => { const [isMobileNavOpen, setMobileNavOpen] = useState(false); const [userState] = React.useContext(UserContext); const location = useLocation(); return ( <DashboardLayoutRoot> <DashboardNavbar onMobileNavOpen={() => setMobileNavOpen(true)} /> <DashboardSidebar onMobileClose={() => setMobileNavOpen(false)} openMobile={isMobileNavOpen} /> <DashboardLayoutWrapper> <DashboardLayoutContainer> <DashboardLayoutContent> {/* 传入需要共享给子路由的状态 */} <Outlet context={{ userInfo: userState.user, isAuth: userState.auth, currentLocation: location }} /> </DashboardLayoutContent> </DashboardLayoutContainer> </DashboardLayoutWrapper> </DashboardLayoutRoot> ); };
子路由组件中直接通过useOutletContext钩子即可拿到共享的状态:
// 示例:在Dashboard组件中获取共享状态 import { useOutletContext } from 'react-router-dom' const Dashboard = () => { const { userInfo, isAuth, currentLocation } = useOutletContext(); // 直接使用拿到的状态即可 return <div>首页内容</div> }
4. 修复登录后回跳逻辑
修改Login组件的登录成功跳转逻辑,完整还原原请求的所有信息:
import { useLocation, useNavigate } from 'react-router-dom' const Login = () => { const navigate = useNavigate(); const location = useLocation(); // 取原请求路径,没有的话默认跳转到仪表盘 const fromPath = location.state?.from || { pathname: '/app/dashboard' }; const handleLoginSuccess = () => { // 登录成功后跳转,完整保留原请求的查询参数、state等信息 navigate(fromPath, { replace: true }); } // 剩余登录页逻辑保持不变 return <div>登录页内容</div> }
内容的提问来源于stack exchange,提问作者Ian Brant
相关产品推荐
相关产品推荐

