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?
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 (
<Route
{...rest}
render={(props) => authed === true
? <Component {...props} />
: <Redirect to={{pathname: '/login', state: {from: props.location}}} />}
/>
)
}
Jetzt können Ihre Routen
etwa so aussehen
<Route path='/' exact component={Home} />
<Route path='/login' component={Login} />
<Route path='/register' component={Register} />
<PrivateRoute authed={this.state.authed} path='/dashboard' component={Dashboard} />
Wenn Sie immer noch verwirrt sind, habe ich diesen Beitrag geschrieben, der vielleicht hilft - Geschützte Routen und Authentifizierung mit React Router v4
Tnx Tyler McGinnis für die Lösung. Ich mache meine Idee von Tyler McGinnis Idee.
const DecisionRoute = ({ trueComponent, falseComponent, decisionFunc, ...rest }) => {
return (
<Route
{...rest}
render={
decisionFunc()
? trueComponent
: falseComponent
}
/>
)
}
Das kann man so implementieren
<DecisionRoute path="/signin" exact={true}
trueComponent={redirectStart}
falseComponent={SignInPage}
decisionFunc={isAuth}
/>
decisionFunc nur eine Funktion, die true oder false zurückgibt
const redirectStart = props => <Redirect to="/orders" />
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 <AuthenticatedRoute>
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 <Route>
-Komponente an die untergeordnete Komponente (<MyComponent>
in diesem Fall) senden.
<Route path='/someprivatepath' render={routeProps => {
if (!this.props.isLoggedIn) {
this.props.redirectToLogin()
return null
}
return <MyComponent {...routeProps} anotherProp={somevalue} />
} />
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