使用TanStack Query实现React登出后重定向异常问题
你的核心问题是登出时['user']查询键失效后,ProtectRoute未自动触发重定向,原因在于手动导航时机过早以及未正确处理查询错误/缓存清除逻辑。以下是具体修复步骤:
1. 移除手动导航,让ProtectRoute自动处理跳转
当前你在登出成功后立即调用navigate,这会导致/home路由下的ProtectRoute被提前卸载,无法等待user查询状态更新。应该删除手动导航,依赖ProtectRoute对用户状态的检测来触发重定向。
2. 替换invalidateQueries为removeQueries
invalidateQueries会标记查询为过时并重新发起profile请求(异步过程),而removeQueries会同步清除user查询的缓存,让useQuery的data立即变为undefined,从而触发ProtectRoute的重定向逻辑。
修改登出逻辑:
const Home = () => { const queryClient = useQueryClient() const mutation = useMutation({ mutationFn: logout, onSuccess: () => { // 直接清除user查询缓存,而非重新请求 queryClient.removeQueries({ queryKey: ['user'] }) // 移除手动navigate调用 }, }) // ...其余代码不变 }
3. 完善ProtectRoute的状态判断
当前ProtectRoute仅判断user是否存在,但未处理profile请求失败(比如登出后请求返回401)的情况。需要加入isError判断,确保任何未登录状态都能触发重定向:
const ProtectRoute = () => { const location = useLocation() const { data: user, isLoading, isError } = useQuery({ queryKey: ['user'], queryFn: profile, retry: false, }) if (isLoading) return <div>...loading</div> // 用户不存在 或 请求失败,都跳转到登录页 if (!user || isError) { return <Navigate to="/signin" state={{ from: location }} replace /> } return <Outlet /> }
4. 确保profile函数正确处理未登录状态
确认profile函数在用户未登录时(比如登出后),要么返回null/undefined,要么抛出错误(比如捕获401状态码并抛出),这样useQuery才能正确更新data或isError状态。
为什么之前的await invalidateQueries无效?
invalidateQueries返回的Promise仅表示“查询已标记为过时并开始重新请求”,而非“重新请求已完成”。即使等待它完成,重新发起的profile请求会因登出返回失败,此时user变为undefined,但你已经手动导航到/signin,ProtectRoute已被卸载,无法触发重定向逻辑。
内容的提问来源于stack exchange,提问作者Tamas Sallai

