web-dev-qa-db-fra.com

Naviguer par programme en utilisant react-router

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.

32
Gaurav Mehta

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 par shouldComponentUpdate, il est important que withRouter enveloppe le fichier composant qui implémente shouldComponentUpdate. 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');
29
Shubham Khatri

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;
3
tgrrr

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.

1
Chris Jaynes
render(){ 

    return (
        <div>  
            { this.props.redirect ? <Redirect to="/" /> :'' } 
            <div>
                add here component codes
            </div>
        </div>
    );
} 
0
Araz Babayev

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

0
reflexgravity

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

0
Denis Rudov