webentwicklung-frage-antwort-db.com.de

React Router private Routen / Umleitung funktioniert nicht

Ich habe das React Router-Beispiel für die privaten Routen leicht angepasst, um Nice mit Redux zu spielen, aber beim Verknüpfen oder Umleiten auf andere "Seiten" werden keine Komponenten gerendert. Das Beispiel finden Sie hier:

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

Ihre PrivateRoute-Komponente sieht folgendermaßen aus:

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

Da ich es jedoch in eine Redux-Anwendung integriert habe, musste ich die PrivateRoute ein wenig anpassen, damit ich auf den Redux-Store sowie auf die Route zugreifen kann.

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

Immer wenn ich nicht angemeldet bin und eine PrivateRoute erreiche, werde ich korrekt zu/login umgeleitet. Nachdem Sie sich jedoch angemeldet und ein <Redirect .../>, oder klicken Sie auf ein <Link ...> für eine PrivateRoute wird der URI aktualisiert, die Ansicht jedoch nicht. Es bleibt auf der gleichen Komponente.

Was mache ich falsch?


Nur um das Bild zu vervollständigen, in der App index.js Es gibt einige irrelevante Dinge und die Routen sind wie folgt aufgebaut:

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')
);
33
Rein

Sie müssen Ihr Route mit dem Tag <Switch> Umschließen

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'));
11
Eli

Stellen Sie die private Route so ein, dass sie nicht rein ist:

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

Dadurch kann die Komponente neu gerendert werden.

Bitte sehen Sie: Reagieren-Router-4-x-privateroute-funktioniert-nicht-nach-dem-Verbinden-mit-Redux .

8
worker11811

Ich hatte gerade das gleiche Problem und löste es, indem ich meinen App-Redux-Container erstellte und isAuthenticated als Requisite an PrivateRoute weitergab

Hier ist es, ich hoffe es hilft

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);

Dann in meiner 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;
6
Danijel

Ich habe es geschafft, mit dem Parameter rest auf die Daten von mapStateToProps zuzugreifen:

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);
5
Newm

Nun, ich denke die Antwort auf diese Frage sollte wirklich detaillierter sein, also bin ich hier, nach 4 Stunden Graben.

Wenn Sie Ihre Komponente mit connect () umschließen, implementiert React Redux shouldComponentUpdate (sCU, wenn Sie Antworten auf Github-Probleme suchen) und führt einen flachen Vergleich für Requisiten durch (es geht durch jeden Schlüssel in den Requisiten) Objekt und überprüfen Sie, ob die Werte mit '===') identisch sind. In der Praxis bedeutet dies, dass Ihre Komponente als Pure betrachtet wird. Es wird sich jetzt nur ändern, wenn sich seine Requisiten ändern und nur dann! Dies ist die Schlüsselbotschaft hier. Zweite Schlüsselbotschaft: React router arbeitet mit dem Kontext, um die Standort-, Übereinstimmungs- und Verlaufsobjekte von Router zu Routenkomponente zu übertragen. Es werden keine Requisiten verwendet. .

Nun wollen wir in der Praxis sehen, was passiert, denn selbst wenn ich das weiß, finde ich es immer noch ziemlich schwierig:

  • Fall 1 :

Nach dem Verbinden gibt es 3 Schlüssel für Ihre Requisiten: Pfad, Komponente und Authentifizierung (von connect angegeben). Tatsächlich wird Ihre umschlossene Komponente bei Routenänderungen NICHT erneut gerendert, da dies nicht wichtig ist. Wenn sich die Route ändert, ändern sich Ihre Requisiten nicht und werden nicht aktualisiert.

  • Fall 3 :

Jetzt gibt es 4 Schlüssel für Ihre Requisiten nach dem Verbinden: Pfad, Komponente, Authentifizierung und Anyprop. Der Trick dabei ist, dass anyprop ein Objekt ist, das bei jedem Aufruf der Komponente erstellt wird. Wenn also Ihre Komponente aufgerufen wird, wird dieser Vergleich durchgeführt: {a: 1} === {a: 1}, was (Sie können es versuchen) falsch macht, sodass Ihre Komponente jetzt jedes Mal aktualisiert wird. Beachten Sie jedoch, dass sich Ihre Komponente immer noch nicht um die Route kümmert, sondern um die untergeordneten Komponenten.

  • Fall 2 :

Das ist hier das Rätsel, denn ich vermute, Sie nennen diese Zeile in Ihrer App-Datei, und es sollte keinen Verweis auf "auth" geben, und Sie sollten einen Fehler haben (zumindest vermute ich das). Ich vermute, dass "auth" in Ihrer App-Datei auf ein dort definiertes Objekt verweist.

Was sollen wir jetzt tun?

Ich sehe hier zwei Möglichkeiten:

  1. Sagen Sie React Redux, dass Ihre Komponente nicht rein ist. Dadurch wird die sCU-Injektion entfernt und Ihre Komponente wird nun korrekt aktualisiert.

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

  2. Verwenden Sie WithRouter (), um das Objekt "Position", "Übereinstimmung" und "Verlauf" als Requisiten in Ihre Komponente einzufügen. Nun, ich kenne die Interna nicht, aber ich vermute, dass React Router diese Objekte nicht mutiert, so dass jedes Mal, wenn sich die Route ändert, sich auch die Requisiten ändern (sCU gibt true zurück) und Ihre Komponente Das hat zur Folge, dass Ihr React Baum jetzt mit viel WithRouter- und Route-Zeug verschmutzt ist ...

Verweis auf das Github-Problem: mgang mit Update-Blockierung

Sie können hier sehen, dass withRouter als Quickfix gedacht ist, aber keine empfohlene Lösung. Die Verwendung von pure: false wird nicht erwähnt, daher weiß ich nicht, wie gut dieses Update sein könnte.

Ich habe eine dritte Lösung gefunden, obwohl mir unklar ist, ob es wirklich eine bessere Lösung ist als mitRouter, wenn Komponenten höherer Ordnung verwendet werden. Sie verbinden Ihre übergeordnete Komponente mit dem Redux-Geschäft, und jetzt ist es Ihrer Route gleichgültig, was sie wiedergibt, das HOC kümmert sich darum.

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);

in deinen App.js

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

Sie können sogar eine Curry-Funktion erstellen, um sie ein wenig zu verkürzen:

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

So verwenden:

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

Ich habe auch mit diesem Problem zu kämpfen, und hier ist meine Lösung.

Anstatt isAuthenticated an jede <PrivateRoute> -Komponente zu übergeben, müssen Sie nur isAuthenticated from state in <PrivateRoute> selbst abrufen.

import React from 'react';
import {Route, Redirect, withRouter} from 'react-router-dom';
import {connect} from 'react-redux';

// isAuthenticated is passed as prop here
const PrivateRoute = ({component: Component, isAuthenticated , ...rest}) => {
    return <Route
        {...rest}
        render={
            props => {
                return isAuthenticated ?
                    (
                        <Component {...props} />
                    )
                    :
                    (
                        <Redirect
                            to={{
                                pathname: "/login",
                                state: {from: props.location}
                            }}
                        />
                    )
            }
        }
    />
};

const mapStateToProps = state => (
    {
        // isAuthenticated  value is get from here
        isAuthenticated : state.auth.isAuthenticated 
    }
);

export default withRouter(connect(
    mapStateToProps, null, null, {pure: false}
)(PrivateRoute));
3
Hoang Trinh

Laut Dokumentation des React-Routers können Sie Ihre connect -Funktion einfach mit withRouter umbrechen:

// before
export default connect(mapStateToProps)(Something)

// after
import { withRouter } from 'react-router-dom'
export default withRouter(connect(mapStateToProps)(Something))

Dies funktionierte für mich und meine Ansichten wurden in diesem Fall zusammen mit den Routen aktualisiert.

1

Ich habe das ähnliche Problem wie @Rein. In meinem Fall sieht PrivateRoute fast genauso aus wie die Originalversion, ist jedoch nur mit Redux verbunden und hat es im Originalbeispiel anstelle von fakeAuth verwendet.

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

 PrivateRoute.propTypes = {
  auth: PropTypes.object.isRequired,
  component: PropTypes.func.isRequired
 }

 const mapStateToProps = (state, ownProps) => {
  return {
     auth: state.auth
  }
};

export default connect(mapStateToProps)(PrivateRoute);

Verwendung und Ergebnis: -

  1. NICHT arbeiten, aber erwarten, dass funktioniert
    • <PrivateRoute path="/member" component={MemberPage} />
  2. funktioniert aber NICHT so verwendet werden soll
    • <PrivateRoute path="/member" component={MemberPage} auth={auth} />
  3. arbeiten. NUR zu arbeiten, aber überhaupt nicht verwendet werden sollen. Ein Verständnis von diesem Punkt ist, dass Sie, wenn Sie Original-PrivateRoute mit Redux verbinden, einige zusätzliche Requisiten (beliebige Requisiten) übergeben müssen, damit PrivateRoute funktioniert. Andernfalls funktioniert es nicht. Jedermann, bitte geben Sie einen Hinweis auf dieses Verhalten . Das ist mein Hauptanliegen. als neue Frage an
    • <PrivateRoute path="/member" component={MemberPage} anyprop={{a:1}} />
0