46 votes

Réagissez les routes privées du routeur / la redirection ne fonctionne pas

J'ai légèrement modifié la Réagir Routeur exemple pour le secteur privé, des itinéraires à jouer gentil avec Redux, mais aucun des composants sont rendus lors de la Liaison ou de Rediriger vers d'autres pages. L'exemple peut être trouvé ici:

https://reacttraining.com/react-router/web/example/auth-workflow

Leur PrivateRoute composant ressemble à ceci:

const PrivateRoute = ({ component: Component, ...rest }) => (
  <Route {...rest} render={props => (
    fakeAuth.isAuthenticated ? (
      <Component {...props}/>
    ) : (
      <Redirect to={{
        pathname: '/login',
        state: { from: props.location }
      }}/>
    )
  )}/>
)

Mais, parce que j'ai incorporé dans un Redux de l'application, j'ai dû régler la PrivateRoute un peu afin que je puisse accéder à la redux magasin, ainsi que le parcours des Accessoires:

const PrivateRouteComponent = (props) => (
    <Route {...props.routeProps} render={() => (
    props.logged_in ? (
        <div>{props.children}</div>
        ) : (
        <Redirect to={{
            pathname: '/login',
            state: { from: props.location }
        }} /> )
    )} />
);

const mapStateToProps = (state, ownProps) => {
    return {
        logged_in: state.auth.logged_in,
        location: ownProps.path,
        routeProps: {
            exact: ownProps.exact,
            path: ownProps.path
        }
    };
};

const PrivateRoute = connect(mapStateToProps, null)(PrivateRouteComponent);
export default PrivateRoute

Chaque fois que je ne suis pas connecté et a frappé un PrivateRoute, je suis correctement redirigé vers /login. Cependant, après par exemple connectant et en utilisant un <Redirect .../>, ou en cliquant sur l'un <Link ...> pour un PrivateRoute, l'URI de mises à jour, mais la vue n'est pas. Il reste sur le même composant.

Ce que je fais mal?


Juste pour compléter le tableau, dans l'application de l' index.js il y a quelques chose sans pertinence, et les itinéraires sont mis en place comme ceci:

ReactDOM.render(
    <Provider store={store}>
        <App>
            <Router>
                <div>
                    <PrivateRoute exact path="/"><Home /></PrivateRoute>
                    // ... other private routes
                    <Route path="/login" component={Login} />
                </div>
            </Router>
        </App>
    </Provider>,
    document.getElementById('root')
);

12voto

Eli Points 119

Vous devez envelopper votre balise Route avec <Switch>

 ReactDOM.render(
<Provider store={store}>
    <App>
        <Router>
            <div>
                <Switch>
                   <PrivateRoute exact path="/"><Home /></PrivateRoute>
                   // ... other private routes
                   <Route path="/login" component={Login} />
                </Switch>
            </div>
        </Router>
    </App>
</Provider>,
document.getElementById('root'));
 

8voto

worker11811 Points 148

Définissez la voie privée pour qu'elle ne soit pas pure:

 export default connect(mapStateToProps, null, null, {
  pure: false,
})(PrivateRoute);
 

Cela laissera le composant rendre à nouveau.

Veuillez consulter: react-router-4-x-privateroute-not-working-after-connection-to-redux .

6voto

Danijel Points 96

Juste le même problème, je l'ai résolu en rendant mon conteneur App redux et en passant isAuthenticated comme accessoire à PrivateRoute

Voilà, j'espère que ça aide

 const App = (props) => {
return (
  <Provider store={store}>
    <Router>
      <div>
        <PrivateRoute path="/secured" component={Secured} isAuthenticated={props.isAuthenticated} />
      </div>
    </Router>
  </Provider>
  );
};

const mapStateToProps = state => ({
  isAuthenticated: state.isAuthenticated
});

export default connect(mapStateToProps)(App);
 

Puis dans mon PrivateRoute

 const PrivateRoute = ({ component: Component, isAuthenticated, ...rest}) => (
<Route
  {...rest}
  render={props => (
    isAuthenticated
    ? (
       <Component {...props} />
    )
    : (<Redirect to={{ pathname: '/login', state: { from: props.location} }} />)
  )}
/>
);

export default PrivateRoute;
 

6voto

Newm Points 384

J'ai réussi à le faire fonctionner en utilisant le paramètre rest pour accéder aux données de mapStateToProps :

 const PrivateRoute = ({component: Component, ...rest}) => {
  const {isAuthenticated} = rest;

  return (
    <Route {...rest} render={props => (
      isAuthenticated ? (
        <Component {...props}/>
      ) : (
        <Redirect to={{
          pathname: '/login',
          state: {from: props.location}
        }}/>
      )
    )}
    />
  );
};

PrivateRoute.propTypes = {
  isAuthenticated: PropTypes.bool.isRequired,
};

function mapStateToProps(state) {
  return {
    isAuthenticated: state.user.isAuthenticated,
  };
}

export default connect(mapStateToProps)(PrivateRoute);
 

4voto

TheoH Points 58

Eh bien, je pense que la réponse à cette question devrait vraiment être plus détaillées, de sorte que je suis ici, après 4 heures de creuser.

Lorsque vous enroulez votre composant avec connect(), Réagir Redux implémente shouldComponentUpdate (sCU si vous cherchez des réponses sur github questions) et de faire peu profonde comparaison sur les accessoires (il va en parcourant chaque clé dans les accessoires de l'objet et de vérifier si les valeurs sont identiques '==='). Ce que cela signifie dans la pratique, c'est que votre composant est considéré comme Pur. Il va maintenant changer seulement quand ses accessoires et ses changements, et seulement ensuite! C'est le message clé ici. Deuxième message clé, de Réagir routeur fonctionne avec le contexte de passer à l'emplacement, match, et l'histoire des objets à partir d'un Routeur pour l'Itinéraire composant. Ne pas utiliser des accessoires.

Maintenant, nous allons voir dans la pratique ce qu'il se passe, parce que même en sachant que, je le trouve toujours assez délicat:

  • Cas 1:

Il y a 3 clés pour votre accessoires après la connexion: chemin d'accès, d'un composant, et auth (donné par la connexion). Donc, en fait, votre enveloppé composant ne sera PAS ré-rendu à tous les changements de route car il n'a pas de soins. Lorsque les modifications d'itinéraire, vos accessoires ne changent pas et il ne sera pas mise à jour.

  • Cas 3:

Maintenant, il y a 4 touches pour votre accessoires après la connexion: chemin d'accès, le composant auth et anyprop. L'astuce ici est que anyprop est un objet qui est créé chaque fois que le composant est appelée. Donc à chaque fois que votre composant est appelé cette comparaison est faite: {a:1} === {a:1}, ce qui (vous pouvez essayer de) vous donne de faux, de sorte que votre composant maintenant les mises à jour à chaque fois. Notez toutefois que votre composant ne se soucient pas de la route, ses enfants.

  • Cas 2:

Maintenant, c'est le mystère ici, parce que je suppose que vous appelez cette ligne dans votre Application fichier, et il devrait y avoir aucune référence à la "auth" là-bas, et vous devriez avoir un message d'erreur (du moins c'est ce que je suis guetting). Ma conjecture est que "auth" dans votre Application fichier fait référence à un objet qui y sont définies.

Maintenant, que devons-nous faire ?

Je vois deux possibilités:

  1. Dites à Réagir Redux que votre composant n'est pas pur, cela permettra d'éliminer l'unité d'injection et de votre composant va maintenant mettre à jour correctement.

    connect(mapStateToProps, null, null, { pure: faux })(PrivateRoute)

  2. Utilisation WithRouter(), qui permettra d'injecter de l'emplacement, la correspondance et l'histoire de l'objet à vos composants comme les accessoires. Maintenant, je ne connais pas le fonctionnement interne, mais je soupçonne Réagir routeur n'est pas muter ces objets de sorte que chaque fois que le changement d'itinéraire, ses accessoires et ses changements (sCU renvoie true (vrai) et ainsi votre composant correctement mises à jour. L'effet secondaire de ceci est que votre Réagissent arbre est maintenant polluée avec beaucoup de WithRouter et de la Route des trucs...

Référence à la github question: Traiter avec la mise à Jour de Blocage

Vous pouvez voir ici que withRouter est conçu comme un quickfix, mais pas une solution recommandée. utilisation pure:faux est pas mentionné donc je ne sais pas comment bon ce correctif pourrait être.

J'ai trouvé une 3ème solution, si c'est pas clair pour moi si c'est vraiment une meilleure solution que withRouter, avec des Composante de l'Ordre. Vous vous connectez à votre Supérieur-Composante de l'ordre de la Redux magasin, et maintenant votre route ne donne pas une merde au sujet de ce qu'il rend, le HOC traite avec elle.

import Notlogged from "./Notlogged";    
function Isloggedhoc({ wrap: Component, islogged, ...props }) {
      return islogged ? <Component {...props} /> : <Notlogged {...props} />;
    }

const mapState = (state, ownprops) => ({
      islogged: state.logged,
      ...ownprops
    });

export default connect(mapState)(Isloggedhoc);

dans votre App.js

<Route path="/PrivateRoute" render={props => <Isloadedhoc wrap={Mycomponent} />} />

Vous pourriez même faire un curry de fonction pour la raccourcir un peu:

function isLogged(component) {
  return function(props) {
    return <Isloadedhoc wrap={component} {...props} />;
  };
}

En l'utilisant comme ça:

<Route path="/PrivateRoute" render={isLogged(Mycomponent)} />

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X