我正在嘗試使用 react context 和 react router v6 路由來構建身份驗證服務,但我無法轉到預期的路由。因此,我的登錄服務正在運行,我正在從后面檢索用戶并在 localStorage 中進行設定,還有一個來自背景關系的狀態來存盤用戶資料 (loggedUser),目前只有 id 和型別。可能有些愚蠢,但 loggedUser 沒有在路由檔案中更新,我不明白為什么,如果它不是背景關系而不是路由,則帶有“警告:無法更新組件(BrowserRouter)同時呈現不同的組件(ClientRoute)。在此先感謝您的幫助!
這是我正在使用的代碼:AuthContext.jsx 檔案(不知道是否也正確地使用了 useEffect 來存盤用戶)
import React, { createContext, useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import user_api from "../Middles/user_api";
export const AuthContext = createContext({});
//Context criado para autentica??o, definir permiss?o de usuário para determinadas rotas
export const AuthProvider = ({ children }) => {
const navigate = useNavigate();
const [loggedUser, setLoggedUser] = useState(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const cachedUser = localStorage.getItem("user");
if(!cachedUser){
console.log("no user");
} else {
console.log("user logged ", cachedUser);
}
if(loggedUser){
localStorage.setItem("user", JSON.stringify(loggedUser));
setIsLoading(false);
navigate('../home', { replace: true });
}
},[loggedUser]);
const login = async (loginValues) => {
try {
const response = await user_api.loginUser(loginValues);
console.log(response.data);
const { userData, token } = response.data;
const user = {
id: userData.id,
type: userData.data.type
}
setLoggedUser(user);
} catch (error) {
console.log(error);
}
}
const logout = () => {
console.log("logout");
}
return(
<AuthContext.Provider value={ {isAuthenticated: !!loggedUser, loggedUser, isLoading, login, logout} }>
{children}
</AuthContext.Provider>
)
}
路由檔案(index.jsx 中的 App_router)
import React, { useContext, useState } from 'react';
import { AuthContext, AuthProvider } from '../Contexts/AuthContext';
import {
BrowserRouter as Router,
Route,
Routes,
useNavigate
} from "react-router-dom";
import HomePage from '../Pages/HomePage';
import Exercises from '../Pages/Exercises';
import UserForm from '../Pages/Forms/UserForm';
import Login from '../Pages/Login';
const App_Router = () => {
const navigate = useNavigate();
const { isAuthenticated, loggedUser, isLoading } = useContext(AuthContext);
const ProRoute = ({ children }) => {
const cachedUser = JSON.parse(localStorage.getItem("user"));
if(cachedUser && cachedUser.type == 'Profissional'){
return children;
}
if(isLoading){
return <section>Carregando...</section>;
}
if(isAuthenticated || loggedUser?.type == "Profissional"){
return children;
}
else {
console.log("Usuário n?o autorizado.");
navigate('/login', {replace: true});
}
}
const ClientRoute = ({ children }) => {
const cachedUser = JSON.parse(localStorage.getItem("user"));
console.log("cachedUser ", cachedUser);
if(cachedUser && cachedUser.type == 'Profissional'){
return children;
}
if(isLoading){
return <section>Carregando...</section>;
}
if(isAuthenticated || loggedUser?.type == "Cliente"){
return children;
}
else {
console.log("Usuário n?o autorizado.");
navigate('/login', {replace: true});
}
}
return (
<AuthProvider>
<Routes>
<Route index path='/' element={<Login />} />
<Route exact path='/login' element={<Login/>}/>
<Route exact path='/register' element={<UserForm/>}/>
<Route
path='/home/Profissional'
element={
<ProRoute>
<HomePage/>
</ProRoute>
}/>
<Route
path='/home'
element={
<ClientRoute>
<HomePage/>
</ClientRoute>
}/>
<Route
path='/home/Profissional/exercises'
element={
<ProRoute>
<Exercises/>
</ProRoute>
}/>
</Routes>
</AuthProvider>
)
}
export default App_Router;
登錄檔案
import React, { useContext, useState } from 'react'
import { Link } from 'react-router-dom';
import { AuthContext } from '../../Contexts/AuthContext';
import user_api from '../../Middles/user_api';
import './styles.css'
//Componente de Login usado para autentica??o e condicionamento de rotas, autentica??o de usuário
const Login = () => {
const { login } = useContext(AuthContext);
const [values, setValues] = useState({
email: '',
password: '',
usertype: ''
});
const handleValues = (e) => {
setValues({...values, [e.target.name]: e.target.value});
}
const handleSubmit = async (e) => {
e.preventDefault();
login(values)
.then(
res => {
setValues({
email: '',
password: '',
usertype: ''
});
})
}
return (
<main id="login-wrapper">
<aside>Chamada de API de treino</aside>
<section id="login-container">
<form onSubmit={handleSubmit}>
<label htmlFor="email">Email</label>
<input type="email" name='email' value={values.email} onChange={handleValues}/>
<label htmlFor="password">Senha</label>
<input type="password" name='password' value={values.password} onChange={handleValues}/>
<a href="">Esqueceu a senha?</a>
<fieldset>
<legend>Tipo:</legend>
<input type="radio" name='usertype' checked={values.usertype === 'Profissional'} value='Profissional' onChange={handleValues} />
<label htmlFor="usertype">Profisisonal</label>
<input type="radio" name='usertype' checked={values.usertype === 'Cliente'} value='Cliente' onChange={handleValues} />
<label htmlFor="">Aluno</label>
</fieldset>
<button type='submit'>Entrar</button>
</form>
</section>
<aside>
<h4>Ainda n?o possui conta?</h4>
<Link to="/register">Cadastre-se</Link>
</aside>
</main>
)
}
export default Login;
這是我嘗試登錄時彈出的完整錯誤日志:
react_devtools_backend.js:4026 Warning: Cannot update a component (`BrowserRouter`) while rendering a different component (`ClientRoute`). To locate the bad setState() call inside `ClientRoute`, follow the stack trace as described in https://reactjs.org/link/setstate-in-render
at ClientRoute (http://localhost:8888/src/Routes/index.jsx:55:5)
at RenderedRoute (http://localhost:8888/node_modules/.vite/deps/react-router-dom.js?v=f7b60e3a:2434:5)
at Routes (http://localhost:8888/node_modules/.vite/deps/react-router-dom.js?v=f7b60e3a:2744:5)
at AuthProvider (http://localhost:8888/src/Contexts/AuthContext.jsx:22:3)
at App_Router (http://localhost:8888/src/Routes/index.jsx:26:20)
請幫忙,我是相對較新的反應,這將不勝感激。謝謝!
uj5u.com熱心網友回復:
代碼的主要問題是受保護的路由組件navigate作為無意的副作用呼叫,即在useEffect掛鉤之外。他們應該navigate從useEffect鉤子中呼叫或者作為更傳統的方法只渲染Navigate組件。可能會或可能不會導致任何問題的次要問題是ProRoute和ClientRoute組件都在另一個 React 組件中宣告;這通常被認為是一種反模式。
自行宣告路由保護組件并重寫以渲染Navigate組件并消費AuthContext.
應用路由器
import {
BrowserRouter as Router,
Route,
Routes,
Navigate,
Outlet,
} from "react-router-dom";
const ProRoute = ({ children }) => {
const { isAuthenticated, loggedUser, isLoading } = useContext(AuthContext);
if (isLoading) {
return <section>Carregando...</section>;
}
if (isAuthenticated || loggedUser?.type == "Profissional") {
return children || <Outlet />;
} else {
return <Navigate to='/login' replace />;
}
}
const ClientRoute = ({ children }) => {
const { isAuthenticated, loggedUser, isLoading } = useContext(AuthContext);
if (isLoading) {
return <section>Carregando...</section>;
}
if (isAuthenticated || loggedUser?.type == "Cliente") {
return children || <Outlet />;
} else {
return <Navigate to='/login' replace />;
}
}
const App_Router = () => {
return (
<AuthProvider>
<Routes>
<Route path='/' element={<Login />} />
<Route path='/login' element={<Login />} />
<Route path='/register' element={<UserForm />} />
<Route path='/home'>
<Route element={<ClientRoute />}>
<Route index element={<HomePage />} />
</Route>
<Route element={<ProRoute />}>
<Route path='Profissional'>
<Route index element={<HomePage />} />
<Route path='exercises' element={<Exercises />} />
</Route>
</Route>
</Route>
</Routes>
</AuthProvider>
);
}
export default App_Router;
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/536491.html
上一篇:如何防止用戶在查詢中修改外鍵?
