Wie implementiert man authentifizierte Routen in React Router 4?

Ich habe versucht, authentifizierte Routen zu implementieren, habe aber festgestellt, dass React Router 4 dies nicht mehr zulässt:

<Route exact path="/" component={Index} />
<Route path="/auth" component={UnauthenticatedWrapper}>
    <Route path="/auth/login" component={LoginBotBot} />
</Route>
<Route path="/domains" component={AuthenticatedWrapper}>
    <Route exact path="/domains" component={DomainsIndex} />
</Route>

Der Fehler ist:

Warnung: Sie sollten <Route component> und <Route children> nicht in derselben Route verwenden; <Route children> wird ignoriert

Was ist in diesem Fall der richtige Weg, dies zu implementieren?

In den react-router (v4) docs wird etwas vorgeschlagen wie

<Router>
    <div>
    <AuthButton/>
    <ul>
        <li><Link to="/public">Public Page</Link></li>
        <li><Link to="/protected">Protected Page</Link></li>
    </ul>
    <Route path="/public" component={Public}/>
    <Route path="/login" component={Login}/>
    <PrivateRoute path="/protected" component={Protected}/>
    </div>
</Router>

Aber ist es möglich, dies zu erreichen, indem man eine Reihe von Routen zusammenfasst?


UPDATE

Ok, nach einigen Recherchen bin ich auf Folgendes gestoßen:

import React, {PropTypes} from "react"
import {Route} from "react-router-dom"

export default class AuthenticatedRoute extends React.Component {
  render() {
    if (!this.props.isLoggedIn) {
      this.props.redirectToLogin()
      return null
    }
    return <Route {...this.props} />
  }
}

AuthenticatedRoute.propTypes = {
  isLoggedIn: PropTypes.bool.isRequired,
  component: PropTypes.element,
  redirectToLogin: PropTypes.func.isRequired
}

Ist es richtig, eine Aktion in render() zu versenden, es fühlt sich falsch an. Es scheint nicht wirklich richtig mit componentDidMount oder einige andere Haken entweder?

Lösung

Sie werden die Komponente Redirect verwenden wollen. Es gibt ein paar verschiedene Ansätze für dieses Problem. Hier ist eine, die ich mag, eine PrivateRoute Komponente, die eine authed Requisite aufnimmt und dann basierend auf dieser Requisite rendert.

function PrivateRoute ({component: Component, authed, ...rest}) {
  return (
     authed === true
        ? 
        : }
    />
  )
}

Jetzt können Ihre Routen etwa so aussehen




Wenn Sie immer noch verwirrt sind, habe ich diesen Beitrag geschrieben, der vielleicht hilft - Geschützte Routen und Authentifizierung mit React Router v4

Kommentare (21)

Tnx Tyler McGinnis für die Lösung. Ich mache meine Idee von Tyler McGinnis Idee.

const DecisionRoute = ({ trueComponent, falseComponent, decisionFunc, ...rest }) => {
  return (

  )
}

Das kann man so implementieren

decisionFunc nur eine Funktion, die true oder false zurückgibt

const redirectStart = props => 
Kommentare (0)

Es scheint, dass Sie zögern, Ihre eigene Komponente zu erstellen und dann in der Render-Methode zu versenden? Nun, Sie können beides vermeiden, indem Sie einfach die Methode render der Komponente Route> verwenden. Es ist nicht nötig, eine Komponente zu erstellen, es sei denn, Sie wollen es wirklich. Sie kann so einfach sein wie unten. Beachten Sie die `{...routeProps}`-Spanne, die sicherstellt, dass Sie weiterhin die Eigenschaften der-Komponente an die untergeordnete Komponente (`` in diesem Fall) senden.

 {

   if (!this.props.isLoggedIn) {
      this.props.redirectToLogin()
      return null
    }
    return 

} />

Siehe die React Router V4 render documentation

Wenn Sie eine dedizierte Komponente erstellen wollten, dann sind Sie wohl auf dem richtigen Weg. Da es sich bei React Router V4 um rein deklaratives Routing handelt (so steht es direkt in der Beschreibung), glaube ich nicht, dass du damit durchkommst, deinen Redirect-Code außerhalb des normalen Komponentenlebenszyklus zu platzieren. Wenn man sich den Code für den React Router selbst ansieht, wird die Umleitung entweder in componentWillMount oder componentDidMount ausgeführt, je nachdem, ob es sich um serverseitiges Rendering handelt oder nicht. Hier ist der folgende Code, der ziemlich einfach ist und Ihnen helfen könnte, sich wohler zu fühlen, wo Sie Ihre Weiterleitungslogik platzieren.

import React, { PropTypes } from 'react'

/**
 * The public API for updating the location programatically
 * with a component.
 */
class Redirect extends React.Component {
  static propTypes = {
    push: PropTypes.bool,
    from: PropTypes.string,
    to: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.object
    ])
  }

  static defaultProps = {
    push: false
  }

  static contextTypes = {
    router: PropTypes.shape({
      history: PropTypes.shape({
        push: PropTypes.func.isRequired,
        replace: PropTypes.func.isRequired
      }).isRequired,
      staticContext: PropTypes.object
    }).isRequired
  }

  isStatic() {
    return this.context.router && this.context.router.staticContext
  }

  componentWillMount() {
    if (this.isStatic())
      this.perform()
  }

  componentDidMount() {
    if (!this.isStatic())
      this.perform()
  }

  perform() {
    const { history } = this.context.router
    const { push, to } = this.props

    if (push) {
      history.push(to)
    } else {
      history.replace(to)
    }
  }

  render() {
    return null
  }
}

export default Redirect
Kommentare (0)