useNavigate()无法跳转至/protected页面问题求助
问题描述
API运行正常,能返回token并保存至localStorage,但调用navigate('/protected')后页面无法跳转;刷新页面可直接进入/protected页面,不想使用强制刷新的临时方案。
相关代码
LoginForm.js
import React, { useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { useMutation } from 'react-query'; import api from './api'; function LoginForm() { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [error, setError] = useState(''); const navigate = useNavigate(); const handleLogin = async () => { const response = await api.post('/authenticate', { email, password }); return response.data; }; const { mutate, isLoading } = useMutation(handleLogin, { onSuccess: (data) => { localStorage.setItem('token', data.token); console.log(data.token); navigate('/protected'); }, onError: (error) => { setError(error.response.data); }, }); const handleSubmit = (e) => { mutate(); e.preventDefault(); }; return ( <form onSubmit={handleSubmit}> <label> Email: <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} /> </label> <label> Password: <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} /> </label> {error && <div>{error}</div>} <button type="submit" disabled={isLoading}> {isLoading ? 'Logging in...' : 'Login'} </button> </form> ); } export default LoginForm;
App.js
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom'; import { useQuery } from 'react-query'; import LoginForm from './LoginForm'; import ProtectedResource from './ProtectedResource'; import api from './api'; function App() { const { isLoading, error, data: isLoggedIn } = useQuery('isLoggedIn', async () => { const token = localStorage.getItem('token'); if (token) { try { await api.get('/resource', { headers: { Authorization: `Bearer ${token}`, }, }); return true; } catch (error) { if (error.response.status === 401) { localStorage.removeItem('token'); } return false; } } else { return false; } }); if (isLoading) return <p>Loading...</p>; if (error) return <p>An error occurred: {error.message}</p>; return ( <Router> <Routes> <Route path="/" element={isLoggedIn ? <Navigate to="/protected" /> : <LoginForm />} /> <Route path="/protected" element={isLoggedIn ? <ProtectedResource /> : <Navigate to="/" />} /> </Routes> </Router> ); } export default App;
问题原因
App组件中通过useQuery('isLoggedIn')判断用户是否登录,这个查询默认只会在组件挂载时执行一次。登录成功后虽然localStorage里的token已更新,但useQuery不会自动重新执行,导致isLoggedIn仍为false。此时调用navigate('/protected')后,路由守卫会因为isLoggedIn为false自动跳回首页,所以看起来页面没有跳转。
解决方案
方法一:登录成功后手动触发查询刷新
利用React Query的useQueryClient,在登录成功后强制刷新isLoggedIn查询,让App组件获取最新的登录状态:
修改LoginForm.js:
- 导入
useQueryClient:
import { useMutation, useQueryClient } from 'react-query';
- 在组件内初始化
queryClient:
const queryClient = useQueryClient();
- 在
onSuccess回调中添加刷新逻辑:
onSuccess: (data) => { localStorage.setItem('token', data.token); console.log(data.token); // 刷新isLoggedIn查询,更新登录状态 queryClient.invalidateQueries('isLoggedIn'); navigate('/protected'); },
方法二:优化表单提交逻辑(非核心,但建议调整)
原代码中handleSubmit先调用mutate()再执行e.preventDefault(),顺序有误,建议调整为:
const handleSubmit = (e) => { e.preventDefault(); mutate(); };
这样修改后,登录成功后isLoggedIn会被更新为true,navigate('/protected')就能正常跳转到保护页面,无需刷新。
内容的提问来源于stack exchange,提问作者Alex Labra
相关产品推荐
相关产品推荐

