Ich entwickle eine Anwendung, in der ich prüfe, ob der Benutzer nicht loggedIn
ist. Ich muss das Anmeldeformular anzeigen, andernfalls dispatch
eine action
, die die Route ändern und andere Komponenten laden würde. Hier ist mein Code:
render() {
if (isLoggedIn) {
// dispatch an action to change the route
}
// return login component
<Login />
}
Wie kann ich das erreichen, da ich den Zustand innerhalb der Renderfunktion nicht ändern kann.
Bedenken Sie, dass Sie react-router v4
verwenden
Verwenden Sie Ihre Komponente mit withRouter
und verwenden Sie history.Push
von Requisiten, um die Route zu ändern. Sie müssen withRouter
nur verwenden, wenn Ihre Komponente keine Router
-Requisiten empfängt. Dies kann in Fällen der Fall sein, in denen Ihre Komponente ein verschachteltes untergeordnetes Element einer vom Router gerenderten Komponente ist und Sie die Router-Requisiten nicht an sie übergeben haben oder wann Die Komponente ist überhaupt nicht mit dem Router verbunden und wird als separate Komponente von den Routen dargestellt.
import {withRouter} from 'react-router';
class App extends React.Component {
...
componenDidMount() {
// get isLoggedIn from localStorage or API call
if (isLoggedIn) {
// dispatch an action to change the route
this.props.history.Push('/home');
}
}
render() {
// return login component
return <Login />
}
}
export default withRouter(App);
Wichtige Notiz
Wenn Sie
withRouter
verwenden, um zu verhindern, dass Updates von .__ blockiert werden.shouldComponentUpdate
, es ist wichtig, dasswithRouter
die .__ umschließt. Komponente, dieshouldComponentUpdate
implementiert. Zum Beispiel, wenn mit Redux:// Das geht um
shouldComponentUpdate
withRouter(connect(...)(MyComponent))
// Das tut nicht
connect(...)(withRouter(MyComponent))
oder Sie könnten Redirect verwenden
import {withRouter} from 'react-router';
class App extends React.Component {
...
render() {
if(isLoggedIn) {
return <Redirect to="/home"/>
}
// return login component
return <Login />
}
}
Mit react-router v2 or react-router v3
können Sie context
verwenden, um die Route dynamisch zu ändern
class App extends React.Component {
...
render() {
if (isLoggedIn) {
// dispatch an action to change the route
this.context.router.Push('/home');
}
// return login component
return <Login />
}
}
App.contextTypes = {
router: React.PropTypes.object.isRequired
}
export default App;
oder verwenden
import { browserHistory } from 'react-router';
browserHistory.Push('/some/path');
In der reakt-router version 4:
import React from 'react'
import { BrowserRouter as Router, Route, Redirect} from 'react-router-dom'
const Example = () => (
if (isLoggedIn) {
<OtherComponent />
} else {
<Router>
<Redirect Push to="/login" />
<Route path="/login" component={Login}/>
</Router>
}
)
const Login = () => (
<h1>Form Components</h1>
...
)
export default Example;
Dies ist mein Handle loggedIn
. react-router v4
PrivateRoute darf path
eingeben, wenn der Benutzer angemeldet ist, und das Token unter localStorge
speichern.
function PrivateRoute({ component: Component, ...rest }) {
return (
<Route
{...rest}
render={props => (localStorage.token) ? <Component {...props} /> : (
<Redirect
to={{
pathname: '/signin',
state: { from: props.location },
}}
/>
)
}
/>
);
}
Definieren Sie hier alle Pfade in Ihrer App
export default (
<main>
<Switch>
<Route exact path="/signin" component={SignIn} />
<Route exact path="/signup" component={SignUp} />
<PrivateRoute path="/" component={Home} />
</Switch>
</main>
);
Eine andere Alternative besteht darin, dies mit asynchronen Aktionen im Thunk-Stil zu behandeln (die sicher sind/Nebeneffekte haben dürfen).
Wenn Sie Thunk verwenden, können Sie dasselbe history
-Objekt sowohl in Ihre <Router>
-Komponente als auch in die Thunk-Aktionen einfügen, indem Sie thunk.withExtraArgument
wie folgt verwenden:
import React from 'react'
import { BrowserRouter as Router, Route, Redirect} from 'react-router-dom'
import { createBrowserHistory } from "history"
import { applyMiddleware, createStore } from "redux"
import thunk from "redux-thunk"
const history = createBrowserHistory()
const middlewares = applyMiddleware(thunk.withExtraArgument({history}))
const store = createStore(appReducer, middlewares)
render(
<Provider store={store}
<Router history={history}>
<Route path="*" component={CatchAll} />
</Router
</Provider>,
appDiv)
In Ihren Aktionserstellern haben Sie eine history
-Instanz, die sicher mit ReactRouter verwendet werden kann. Sie können also einfach ein reguläres Redux-Ereignis auslösen, wenn Sie nicht angemeldet sind:
// meanwhile... in action-creators.js
export const notLoggedIn = () => {
return (dispatch, getState, {history}) => {
history.Push(`/login`)
}
}
Ein weiterer Vorteil ist, dass die URL jetzt einfacher zu handhaben ist, sodass wir Weiterleitungsinformationen in die Abfragezeichenfolge usw. einfügen können.
Sie können auch weiterhin versuchen, diese Überprüfung in Ihren Render-Methoden durchzuführen. Wenn dies jedoch Probleme verursacht, sollten Sie dies in componentDidMount
oder an anderer Stelle im Lebenszyklus tun (obwohl ich auch den Wunsch verstehe, bei Stateless Functional Compeonents zu bleiben!)
Sie können weiterhin Redux und mapDispatchToProps
verwenden, um den Aktionsersteller in Ihr Unternehmen einzuspeisen, sodass Ihre Komponente nur noch lose mit Redux verbunden ist.
Ich konnte history
in zustandslosen Funktionskomponenten mit withRouter wie folgt verwenden (erforderlich, um die TypeScript-Warnung zu ignorieren):
import { withRouter } from 'react-router-dom';
...
type Props = { myProp: boolean };
// @ts-ignore
export const MyComponent: FC<Props> = withRouter(({ myProp, history }) => {
...
})
render(){
return (
<div>
{ this.props.redirect ? <Redirect to="/" /> :'' }
<div>
add here component codes
</div>
</div>
);
}
Diejenigen, die Probleme bei der Implementierung auf reag-router v4 haben. Hier ist eine funktionierende Lösung für die programmgesteuerte Navigation durch die Apprea.
history.js
import createHistory from 'history/createBrowserHistory'
export default createHistory()
App.js OR Route.jsx. Übergeben Sie die Geschichte als Requisite an Ihren Router.
import { Router, Route } from 'react-router-dom'
import history from './history'
...
<Router history={history}>
<Route path="/test" component={Test}/>
</Router>
Sie können Push()
zum Navigieren verwenden.
import history from './history'
...
render() {
if (isLoggedIn) {
history.Push('/test') // this should change the url and re-render Test component
}
// return login component
<Login />
}
Vielen Dank für diesen Kommentar: https://github.com/ReactTraining/react-router/issues/3498#issuecomment-301057248
Ich würde vorschlagen, dass Sie Connected-React-Routerhttps://github.com/supasate/connected-react-router es ist gut dokumentiert und einfach zu konfigurieren