recherche

Maison  >  Questions et réponses  >  le corps du texte

Titre réécrit en : Les routes protégées dans React Route v6 ne se mettent pas à jour lorsque l'utilisateur se connecte

<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>
P粉297434909P粉297434909451 Il y a quelques jours459

répondre à tous(1)je répondrai

  • P粉043432210

    P粉0434322102023-08-30 12:24:05

    Le problème est que le gestionnaire de connexion émet deux actions en même temps.

    onClick={() => {
      dispatch(loginUser({ email, password })); // <-- 登录用户
      navigate('/recipes');                     // <-- 立即导航
    }}
    

    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.

    const loginHandler = async () => {
      try {
        const response = await dispatch(loginUser({ email, password })).unwrap();
        if (/* 检查响应条件 */) {
          navigate("/recipes", { replace: true });
        }
      } catch (error) {
        // 处理任何错误或被拒绝的 Promise
      }
    };
    
    ...
    
    
    onClick={loginHandler}
    

    Voir Gestion des résultats Thunk pour plus de détails.

    Vous pouvez également simplifier votre ProtectedRoutelogique 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.

    export default function ProtectedRoute() {
      const user = useSelector((state) => state.user);
    
      if (user.isLoading) {
        return null; // 或者加载指示器/旋转器等
       }
    
      return user.success ? <Outlet /> : <Navigate to="/login" replace />;
    }

    répondre
    0
  • Annulerrépondre