標題重寫為:使用者登入時,React Route v6中的受保護路由未更新
P粉297434909
2023-08-29 15:00:09
<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 } 從 '../../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>
問題在於登入處理程序同時發出了兩個動作。
在使用者進行身份驗證之前,導航到受保護的路由。
為了解決這個問題,登入處理程序應該等待成功的身份驗證,然後重定向到所需的路由。
更多詳細資訊請參考處理 Thunk 結果。
您也可以簡化
ProtectedRoute
邏輯,不需要額外的重新渲染,只需取得正確的輸出進行渲染。所有路由保護狀態都可以從所選的 redux 狀態中派生。