Titre réécrit en : Les routes protégées dans React Route v6 ne se mettent pas à jour lorsque l'utilisateur se connecte
P粉297434909
2023-08-29 15:00:09
<p>J'essaie de connecter un utilisateur. J'ai un composant de connexion qui reçoit les informations d'identification, puis j'utilise la boîte à outils redux pour stocker l'état et la validation et tout se fait dans userSlice. J'ai un itinéraire protégé qui doit vérifier si l'utilisateur est connecté et si l'utilisateur n'est pas connecté, il ne doit pas accéder à la page de recette que j'ai. Lorsque j'essaie d'accéder à l'utilisateur à partir d'un composant de routage protégé à l'aide du hook useSelecter, il renvoie null au premier rendu, mais renvoie l'utilisateur au deuxième rendu, mais la connexion échoue toujours. Dans les outils de développement Redux, le statut est bien mis à jour. Existe-t-il un moyen d'obtenir l'objet utilisateur lors du premier rendu du composant de routage protégé ? (Comme vous pouvez le voir, j'utilise le hook useEffect et j'ai un tableau de dépendances). </p>
<p>Merci beaucoup pour votre aide.
Merci. </p>
<p>Voici mon code : </p>
<p>Login.js -- Ce fichier est chargé de recevoir les informations d'identification, de distribuer une action à l'aide de useDispatch et de mettre à jour l'état à l'aide de useDispatch. </p>
<pre class="brush:php;toolbar:false;">importer React, { useState } depuis 'react';
importer { loginUser } depuis '../../features/users/userSlice' ;
importer { useSelector, useDispatch } depuis 'react-redux'
importer { useNavigate } depuis 'react-router-dom' ;
exporter la fonction par défaut Login() {
const [email, setEmail] = useState("");
const [mot de passe, setPassword] = useState("");
const user = useSelector(state => state.user.user)
const dispatch = useDispatch()
const naviguer = useNavigate()
retour (
<div>
<entrée
type="texte"
valeur={e-mail}
onChange={(e) => setEmail(e.target.value)}
/>
<entrée
type="mot de passe"
valeur={mot de passe}
onChange={(e) => setPassword(e.target.value)}
/>
<type de bouton="soumettre" onClick={() =>
dispatch(loginUser({email, mot de passe}))
naviguer('/recettes')
}}>soumettre</bouton>
</div>
)
}</pré>
<p>ProtectedRoute.js -- Ce composant garantit que si l'utilisateur n'est pas authentifié, il ne pourra pas se connecter</p>
<pre class="brush:php;toolbar:false;">importer React, { useState, useEffect } depuis "react" ;
importer { Route, Navigate, Outlet } depuis "react-router-dom" ;
importer { useSelector } depuis 'react-redux' ;
exporter la fonction par défaut ProtectedRoute({ enfants }) {
const [ activeUser, setActiveUser ] = useState (faux)
const user = useSelector((state) => state.user);
useEffect(() => {
si (!user.isLoading) {
utilisateur.succès ? setActiveUser(true) : setActiveUser(false)
console.log('utilisateur actif : ' + utilisateuractif)
}
}, [utilisateur])
retour (
activeUser ? <Outlet /> : <Accéder à="/login"/>
)
}</pré>
<p>app.js -- Ce composant contient toutes les routes, y compris les routes protégées. </p>
<pre class="brush:php;toolbar:false;">importer React depuis "react" ;
importer des recettes depuis "./components/recipes/recipes" ;
importer la connexion depuis "./components/users/Login" ;
importer { BrowserRouter, Routes, Route, Navigate } depuis "react-router-dom" ;
importer ProtectedRoute depuis "./utils.js/ProtectedRoute";
const App = () =>
retour (
<div>
<NavigateurRouter>
<Itinéraires>
<Chemin d'itinéraire="/connexion" élément d'index={<Connexion />} />
<Route path="/" element={<Navigate replace to="/login" />}/>
<Élément d'itinéraire={<ProtectedRoute />}>
<Élément d'itinéraire={<Recettes/>} chemin="/recettes" />
</Itinéraire>
</Itinéraires>
</NavigateurRouter>
</div>
);
} ;
exporter l'application par défaut ;</pre>
<p>userSlice.js -- Boîte à outils Redux pour les tranches, et les réducteurs pour les tranches.</p>
<pre class="brush:php;toolbar:false;">import { createSlice, createAsyncThunk } depuis "@reduxjs/toolkit" ;
importer des axios depuis "axios" ;
const loginUrl = 'http://localhost:5000/api/login';
const signupUrl = 'http://localhost:5000/api/signup';
export const loginUser = createAsyncThunk('user/loginUser', async (data) => {
const réponse = attendre axios.post (loginUrl, data);
réponse de retour ;
})
export const signupUser = createAsyncThunk('user/signupUser', async (data) => {
const réponse = attendre axios.post(signupUrl, data);
réponse de retour ;
})
const état initial = {
utilisateur: {},
isLoading : vrai
}
const userSlice = créerSlice({
nom : 'utilisateur',
Etat initial,
réducteurs : {
getPassword : (état, action) => {
const mot de passe = action.payload
console.log(mot de passe)
}
},
extraRéducteurs : {
[loginUser.ending] : (état) => {
state.isLoading = faux
},
[loginUser.fulfilled] : (état, action) => {
state.isLoading = faux
état.utilisateur = action.payload.data
},
[loginUser.rejected] : (état) => {
state.isLoading = faux
},
[signupUser.ending] : (état) => {
state.isLoading = faux
},
[signupUser.fulfilled] : (état, action) => {
state.isLoading = faux
état.utilisateur = action.payload.data
},
[signupUser.rejected] : (état) => {
state.isLoading = faux
},
}
})
exporter const { getPassword } = userSlice.actions
exporter userSlice.reducer;</pre></p>
Le problème est que le gestionnaire de connexion émet deux actions en même temps.
Accédez aux itinéraires protégés avant que les utilisateurs ne s'authentifient.
Pour résoudre ce problème, le gestionnaire de connexion doit attendre une authentification réussie, puis rediriger vers la route requise.
Voir Gestion des résultats Thunk pour plus de détails.
Vous pouvez également simplifier votre
ProtectedRoute
logique afin qu'aucun nouveau rendu supplémentaire ne soit nécessaire, obtenez simplement la sortie correcte à restituer. Tous les états de garde de route peuvent être dérivés d'états redux sélectionnés.