当
/dashboard
不是 user
时,应用程序应重定向到 null
。用户在第一次渲染中是 null
,但 useEffect()
应该从本地存储中获取并存储用户数据。然后,三元运算符应该触发 <Redirect to='/dashboard' />
并重定向到仪表板页面。但是,它并没有这样做。每当我刷新时,即使 localStorage 中有数据,它也会一直在 /login
显示登录页面。
我做错了什么或者如何解决这个问题?
const App = () => {
const [user, setUser] = useState(null)
useEffect(() => {
const loggedUserJSON = window.localStorage.getItem('loggedUser')
if (loggedUserJSON) {
const user = JSON.parse(loggedUserJSON)
setUser(user)
noteService.setToken(user.token)
}
}, [])
return (
<Router>
<Switch>
<Route exact path='/'>
{user
? <Redirect to='/dashboard' />
: <Redirect to='/login' />
}
</Route>
<Route exact path='/login'>
<LogIn />
</Route>
<Route exact path='/dashboard'>
<Dashboard />
</Route>
</Switch>
</Router>
)
问题是,在初始渲染时,
user
状态为null
,并且会重定向到“/login”。当您重新加载页面时,如果路径仍然是“/login”,则无论 user
状态如何,它都不会完全匹配“/”,并且不会发生重定向。
从 localStorage 初始化状态,而不是等待渲染周期。这至少允许您在第一次渲染而不是在第二次(或更高版本)重新渲染时检查
user
状态。对 Switch
组件中的路由进行重新排序,以从 more 特定到 less 特定进行指定。重定向应该放在最后,以便其他路径有机会首先匹配和渲染。
const initializeState = () => JSON.parse(window.localStorage.getItem('loggedUser'));
const App = () => {
const [user] = useState(initializeState());
useEffect(() => {
noteService.setToken(user.token);
}, [user]);
return (
<Router>
<Switch>
<Route path='/login'>
<LogIn />
</Route>
<Route path='/dashboard'>
<Dashboard />
</Route>
<Redirect to={user ? '/dashboard' : '/login'} />
</Switch>
</Router>
);
};
这并不能完全解决用户已经在子路由上的页面重新加载问题。为此,您应该实现一个
ProtectedRoute
组件并将user
状态作为道具传递。如果存在 user
对象,它会渲染常规 Route
组件并传递道具,否则它会渲染 Redirect
并将用户弹回登录路由。
const ProtectedRoute = ({ user, ...props }) => user ? (
<Route {...props} />
) : (
<Redirect to="/login" />
);
const initializeState = () => JSON.parse(window.localStorage.getItem('loggedUser'));
const App = () => {
const [user] = useState(initializeState());
useEffect(() => {
noteService.setToken(user.token);
}, [user]);
return (
<Router>
<Switch>
<Route path='/login'>
<LogIn />
</Route>
<ProtectedRoute path='/dashboard' user={user} >
<Dashboard />
</ProtectedRoute>
<Redirect to={user ? '/dashboard' : '/login'} />
</Switch>
</Router>
);
};
如果您使用的是版本 6,请阅读以下内容:reactrouter.com/docs/en/v6/upgrading/v5
特别是它告诉您删除直接位于
<Redirect>
内的任何 <Switch>
元素的部分。