Je développe une application dans laquelle je vérifie si l'utilisateur n'est pas loggedIn
. Je dois afficher le formulaire de connexion, sinon dispatch
une action
qui changerait l'itinéraire et chargerait un autre composant. Voici mon code:
render() {
if (isLoggedIn) {
// dispatch an action to change the route
}
// return login component
<Login />
}
Comment puis-je atteindre cet objectif car je ne peux pas changer les états dans la fonction de rendu.
Considérant que vous utilisez react-router v4
Utilisez votre composant avec withRouter
et utilisez history.Push
depuis les accessoires pour modifier l'itinéraire. Vous devez utiliser withRouter
uniquement lorsque votre composant ne reçoit pas les accessoires Router
. Cela peut se produire lorsque votre composant est un enfant imbriqué d'un composant rendu par le routeur et que vous ne lui avez pas transmis les accessoires du routeur ou lorsque le composant n'est pas du tout lié au routeur et est rendu en tant que composant distinct des itinéraires.
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);
Note importante
Si vous utilisez
withRouter
pour empêcher le blocage des mises à jour parshouldComponentUpdate
, il est important quewithRouter
enveloppe le fichier composant qui implémenteshouldComponentUpdate
. Par exemple, quand en utilisant Redux:// Ceci circule
shouldComponentUpdate
withRouter(connect(...)(MyComponent))
// Cela ne veut pas
connect(...)(withRouter(MyComponent))
ou vous pouvez utiliser Redirect
import {withRouter} from 'react-router';
class App extends React.Component {
...
render() {
if(isLoggedIn) {
return <Redirect to="/home"/>
}
// return login component
return <Login />
}
}
Avec react-router v2 or react-router v3
, vous pouvez utiliser context
pour modifier l’itinéraire de manière dynamique, comme ceci:
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;
ou utiliser
import { browserHistory } from 'react-router';
browserHistory.Push('/some/path');
Dans react-routeur 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;
Une autre alternative est de gérer cela en utilisant des actions asynchrones de style Thunk (qui sont sûres/autorisées à avoir des effets secondaires).
Si vous utilisez Thunk, vous pouvez injecter le même objet history
dans votre action <Router>
et vos actions Thunk à l'aide de thunk.withExtraArgument
, comme suit:
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)
Ensuite, dans vos créateurs d’action, vous aurez une instance history
qui peut être utilisée en toute sécurité avec ReactRouter. Vous pouvez donc déclencher un événement Redux normal si vous n’êtes pas connecté:
// meanwhile... in action-creators.js
export const notLoggedIn = () => {
return (dispatch, getState, {history}) => {
history.Push(`/login`)
}
}
Un autre avantage est que l'URL est plus facile à gérer, maintenant, nous pouvons donc mettre des informations de redirection sur la chaîne de requête, etc.
Vous pouvez toujours essayer de faire cette vérification dans vos méthodes de rendu, mais si cela pose problème, vous pouvez envisager de le faire dans componentDidMount
, ou ailleurs dans le cycle de vie (bien que je comprenne aussi le désir de rester avec des représentants fonctionnels sans état!)
Vous pouvez toujours utiliser Redux et mapDispatchToProps
pour injecter le créateur d'action dans votre composant, de sorte que votre composant n'est toujours connecté que vaguement à Redux.
render(){
return (
<div>
{ this.props.redirect ? <Redirect to="/" /> :'' }
<div>
add here component codes
</div>
</div>
);
}
Ceux qui rencontrent des problèmes lors de l’implémentation de ceci sur react-router v4. Voici une solution de travail pour naviguer dans l'application de réaction par programme.
histoire.js
import createHistory from 'history/createBrowserHistory'
export default createHistory()
App.js OR Route.jsx. Transmettez l’historique comme accessoire à votre routeur.
import { Router, Route } from 'react-router-dom'
import history from './history'
...
<Router history={history}>
<Route path="/test" component={Test}/>
</Router>
Vous pouvez utiliser Push()
pour naviguer.
import history from './history'
...
render() {
if (isLoggedIn) {
history.Push('/test') // this should change the url and re-render Test component
}
// return login component
<Login />
}
Tout cela grâce à ce commentaire: https://github.com/ReactTraining/react-router/issues/3498#issuecomment-301057248
Je vous suggère d'utiliser connected-react-routerhttps://github.com/supasate/connected-react-router , Ce qui facilite la navigation, même à partir de réducteurs/actions, si vous le souhaitez. . il est bien documenté et facile à configurer