API 工作正常,它返回 token ,然后保存在我的本地内存中,但由于某种原因它不会重定向。如果我刷新窗口,我会直接进入 "/protected"
页。
登录表单.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
因为 protected 页面并不重要,因为它只有 <h1></h1>
。我的 API 也不适用,因为我毫无问题地获得了所需的 token 。唯一的问题是重定向。我确实强制窗口重新加载,但这是一种我打赌不安全的解决方法?
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;
最佳答案
代码使用 localStorage
作为事实来源,但更新 localStorage 不会触发 App
React 组件使用新的身份验证值重新渲染,以便正确地进行渲染。必要时保护路由或重定向。 token 值存储在 localStorage 中,并且到 "/protected"
的导航操作生效,但由于 App
没有重新渲染,因此 useQuery
钩子(Hook)没有重新运行来检查用户的 token 值。
重构代码以将状态添加到App
,该状态在成功登录和退出时更新。这将触发App
重新渲染并重新运行useQuery
并检查存储的token
值。
示例:
export default function App() {
const [token, setToken] = React.useState(); // <-- state
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 (
...
<Routes>
<Route
path="/"
element={
isLoggedIn ? (
<Navigate to="/protected" />
) : (
<LoginForm setToken={setToken} /> // <-- pass setter
)
}
/>
<Route
path="/protected"
element={isLoggedIn ? <ProtectedResource /> : <Navigate to="/" />}
/>
</Routes>
...
);
}
function LoginForm({ setToken }) { // <-- consume setToken callback
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);
setToken(data.token); // <-- update token state
navigate("/protected");
},
onError: (error) => {
setError(error.response.data);
}
});
const handleSubmit = (e) => {
mutate();
e.preventDefault();
};
return (
<form onSubmit={handleSubmit}>
...
</form>
);
}
演示
关于javascript - useNavigate() 未重定向到 '/protected',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75982328/