Zustand更新存储后TanStack Router仍重定向的登录问题求助
解决Zustand + TanStack Router登录时状态更新滞后导致重定向失败的问题
你遇到的核心问题是:第一次点击登录后,Zustand的auth状态更新与路由跳转时机不匹配——路由守卫读取的是Router Context中未更新的旧状态,因此触发重定向回登录页;第二次点击时状态已完成更新,守卫读取到正确状态后正常跳转。
问题根源在于App.tsx中将Zustand的当前state快照传递给了RouterProvider的context,状态更新后Router Context的同步存在滞后,导致导航时守卫无法获取最新状态。
步骤1:传递Zustand Store实例而非状态快照
不要将当前的auth state传给Router Context,而是传递Zustand的store实例,让路由守卫可以随时获取最新状态。
修改store.ts
确保导出Zustand的store实例(或getState方法):
import { create } from 'zustand'; const useGlobalStore = create((set) => ({ user: null, login: async (credentials) => { const res = await fetch('/api/login', { method: 'POST', body: JSON.stringify(credentials), }); const user = await res.json(); set({ user }); }, // 其他auth相关方法 })); // 导出获取最新状态的方法,用于非组件环境(如路由守卫) export const getAuthState = useGlobalStore.getState; export default useGlobalStore;
修改App.tsx
将store的getState方法传入Router Context,而非当前状态:
import { RouterProvider } from '@tanstack/react-router'; import { MantineProvider } from '@mantine/core'; import useGlobalStore, { getAuthState } from './store'; import { router } from './router'; import { workshopWizardTheme, wwVariablesResolver } from './theme'; const App = () => { return ( <MantineProvider theme={workshopWizardTheme} cssVariablesResolver={wwVariablesResolver}> <RouterProvider router={router} context={{ getAuthState }} /> </MantineProvider> ); }; export default App;
步骤2:在路由守卫中获取最新状态
修改AppRoute的beforeLoad逻辑,通过传入的getAuthState方法获取实时的auth状态:
// App Route示例 export const Route = createFileRoute('/app')({ beforeLoad: async ({ context }) => { // 获取最新的auth状态 const authState = context.getAuthState(); if (!authState.user) { return { redirect: { to: '/auth/login', }, }; } }, // 其他路由配置 });
步骤3:确保登录完成后再跳转
在AuthPage中,等待登录action执行完成(状态更新后)再执行路由跳转:
import { useRouter } from '@tanstack/react-router'; import useGlobalStore from './store'; const AuthPage = () => { const router = useRouter(); const { login } = useGlobalStore(); const handleLogin = async (credentials) => { // 等待登录状态更新完成 await login(credentials); // 跳转至首页 router.navigate({ to: '/' }); }; return ( // 登录表单代码 <button onClick={() => handleLogin({ username, password })}>登录</button> ); }; export default AuthPage;
额外说明
- 避免将可变的状态快照传入Router Context,因为Context的更新依赖组件重渲染,无法保证与状态更新同步。
- 使用Zustand的
getState()方法可以在任何环境(包括路由守卫这种非组件场景)获取最新状态,确保路由判断的准确性。
内容的提问来源于stack exchange,提问作者Unknown
相关产品推荐
相关产品推荐

