标题重写为:用户登录时,React Route v6中的受保护路由未更新
<p>我正在尝试登录用户。我有一个登录组件,它接收凭据,然后我使用redux toolkit来存储状态,并且验证和所有操作都在userSlice中完成。我有一个受保护的路由,应该检查用户是否已登录,如果用户未登录,则不应导航到我拥有的食谱页面。当我尝试使用useSelecter hook从受保护的路由组件访问用户时,它在第一次渲染时返回空,但在第二次渲染时确实返回用户,但登录仍然失败。在redux dev tools中,状态被更新得很好。是否有一种方法可以在受保护的路由组件的第一次渲染中获取用户对象?(正如您所看到的,我正在使用useEffect hook,并且有依赖数组)。</p>
<p>非常感谢您的帮助。
谢谢。</p>
<p>下面是我的代码:</p>
<p>Login.js -- 这个文件负责接收凭据,然后使用useDispatch分派一个动作并使用useDispatch更新状态。</p>
<pre class="brush:php;toolbar:false;">import React, { useState } from 'react';
import { loginUser } from '../../features/users/userSlice';
import { useSelector, useDispatch } from 'react-redux'
import { useNavigate } from 'react-router-dom';
export default function Login() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const user = useSelector(state => state.user.user)
const dispatch = useDispatch()
const navigate = useNavigate()
return (
<div>
<input
type="text"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button type="submit" onClick={() => {
dispatch(loginUser({email, password}))
navigate('/recipes')
}}>submit</button>
</div>
)
}</pre>
<p>ProtectedRoute.js -- 此组件确保如果用户未经身份验证,他将无法登录</p>
<pre class="brush:php;toolbar:false;">import React, { useState, useEffect } from "react";
import { Route, Navigate, Outlet } from "react-router-dom";
import { useSelector } from 'react-redux';
export default function ProtectedRoute({ children }) {
const [ activeUser, setActiveUser ] = useState(false)
const user = useSelector((state) => state.user);
useEffect(() => {
if (!user.isLoading) {
user.success ? setActiveUser(true) : setActiveUser(false)
console.log('active user: ' + activeUser)
}
}, [user])
return (
activeUser ? <Outlet /> : <Navigate to="/login"/>
)
}</pre>
<p>app.js -- 此组件包含所有路由,包括受保护的路由。</p>
<pre class="brush:php;toolbar:false;">import React from "react";
import Recipes from "./components/recipes/recipes";
import Login from "./components/users/Login";
import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom";
import ProtectedRoute from "./utils.js/ProtectedRoute";
const App = () => {
return (
<div>
<BrowserRouter>
<Routes>
<Route path="/login" index element={<Login />} />
<Route path="/" element={<Navigate replace to="/login" />}/>
<Route element={<ProtectedRoute />}>
<Route element={<Recipes/>} path="/recipes" />
</Route>
</Routes>
</BrowserRouter>
</div>
);
};
export default App;</pre>
<p>userSlice.js -- 由于我使用redux toolkit,因此我有不同功能的slices。这里有reducers,其中有用户状态。</p>
<pre class="brush:php;toolbar:false;">import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import axios from "axios";
const loginUrl = 'http://localhost:5000/api/login';
const signupUrl = 'http://localhost:5000/api/signup';
export const loginUser = createAsyncThunk('user/loginUser', async (data) => {
const response = await axios.post(loginUrl, data);
return response;
})
export const signupUser = createAsyncThunk('user/signupUser', async (data) => {
const response = await axios.post(signupUrl, data);
return response;
})
const initialState = {
user: {},
isLoading: true
}
const userSlice = createSlice({
name: 'user',
initialState,
reducers: {
getPassword: (state, action) => {
const password = action.payload
console.log(password)
}
},
extraReducers: {
[loginUser.pending]: (state) => {
state.isLoading = false
},
[loginUser.fulfilled]: (state, action) => {
state.isLoading = false
state.user = action.payload.data
},
[loginUser.rejected]: (state) => {
state.isLoading = false
},
[signupUser.pending]: (state) => {
state.isLoading = false
},
[signupUser.fulfilled]: (state, action) => {
state.isLoading = false
state.user = action.payload.data
},
[signupUser.rejected]: (state) => {
state.isLoading = false
},
}
})
export const { getPassword } = userSlice.actions
export default userSlice.reducer;</pre></p>