Comment passer à l’histoire dans React Router v4?

Dans la version actuelle de React Router (v3), je peux accepter une réponse du serveur et utiliser browserHistory.push pour accéder à la page de réponse appropriée. Cependant, ce n’est pas disponible dans la version 4, et je ne suis pas sûr de la manière appropriée de gérer cela.

Dans cet exemple, en utilisant Redux, components / app-product-form.js appelle this.props.addProduct(props) lorsqu’un utilisateur soumet le formulaire. Lorsque le serveur renvoie un succès, l’utilisateur accède à la page du panier.

 // actions/index.js export function addProduct(props) { return dispatch => axios.post(`${ROOT_URL}/cart`, props, config) .then(response => { dispatch({ type: types.AUTH_USER }); localStorage.setItem('token', response.data.token); browserHistory.push('/cart'); // no longer in React Router V4 }); } 

Comment puis-je effectuer une redirection vers la page Cart depuis la fonction React Router v4?

    Vous pouvez utiliser les méthodes d’ history dehors de vos composants. Essayez de la manière suivante.

    Tout d’abord, créez un object d’ history utilisant le package d’historique :

     // src/history.js import { createBrowserHistory } from 'history'; export default createBrowserHistory(); 

    Ensuite, enveloppez-le dans ( veuillez noter que vous devez utiliser import { Router } au lieu d’ import { BrowserRouter as Router } ):

     // src/index.jsx // ... import { Router, Route, Link } from 'react-router-dom'; import history from './history'; ReactDOM.render(   
    • Home
    • Login
    , document.getElementById('root'), );

    Changez votre emplacement actuel à partir de n’importe quel endroit, par exemple:

     // src/actions/userActionCreators.js // ... import history from '../history'; export function login(credentials) { return function (dispatch) { return loginRemotely(credentials) .then((response) => { // ... history.push('/'); }); }; } 

    UPD : Vous pouvez également voir un exemple légèrement différent dans la FAQ de React Router .

    React Router v4 est fondamentalement différent de v3 (et antérieur) et vous ne pouvez pas faire browserHistory.push() comme vous le browserHistory.push() auparavant.

    Cette discussion semble liée si vous voulez plus d’informations:

    • La création d’un browserHistory ne fonctionnera pas car crée sa propre instance d’historique et écoute les modifications apscopes. Ainsi, une instance différente modifiera l’URL mais ne pas à jour le .
    • browserHistory n’est pas exposé par react-router dans v4, mais uniquement dans v2.

    Au lieu de cela, vous avez quelques options pour le faire:

    • Utilisez le withRouter haut niveau withRouter

      Au lieu de cela, vous devez utiliser le withRouter haut niveau withRouter , et envelopper le composant qui sera transmis à l’historique. Par exemple:

       import React from "react"; import { withRouter } from "react-router-dom"; class MyComponent extends React.Component { ... myFunction() { this.props.history.push("/some/Path"); } ... } export default withRouter(MyComponent); 

      Consultez la documentation officielle pour plus d’informations:

      Vous pouvez accéder aux propriétés de l’object history et à la correspondance la plus proche via le composant d’ordre supérieur withRouter. withRouter restaure son composant à chaque fois que la route change avec les mêmes propriétés que render props: { match, location, history } .


    • Utiliser l’API context

      L’utilisation du contexte peut être l’une des solutions les plus simples, mais étant une API expérimentale, elle est instable et non prise en charge. Utilisez-le uniquement lorsque tout le rest échoue. Voici un exemple:

       import React from "react"; import PropTypes from "prop-types"; class MyComponent extends React.Component { static contextTypes = { router: PropTypes.object } constructor(props, context) { super(props, context); } ... myFunction() { this.context.router.history.push("/some/Path"); } ... } 

      Consultez la documentation officielle sur le contexte:

      Si vous souhaitez que votre application soit stable, n’utilisez pas de contexte. C’est une API expérimentale et elle risque de se briser dans les futures versions de React.

      Si vous insistez pour utiliser le contexte malgré ces avertissements, essayez d’isoler votre utilisation du contexte dans une zone restreinte et évitez d’utiliser l’API de contexte directement lorsque cela est possible, afin de faciliter la mise à niveau lorsque l’API change.

    C’est comme ça que je l’ai fait:

     import React, {Component} from 'react'; export default class Link extends Component { constructor(props) { super(props); this.onLogout = this.onLogout.bind(this); } onLogout() { this.props.history.push('/'); } render() { return ( 

    Your Links

    ); } }

    Utilisez this.props.history.push('/cart'); pour redirect vers la page du panier, il sera enregistré dans l’object historique.

    Profitez-en, Michael.

    Selon la documentation de React Router v4 – Session Redux Deep Integration

    Une intégration profonde est nécessaire pour:

    “être capable de naviguer en envoyant des actions”

    Cependant, ils recommandent cette approche comme alternative à “l’intégration profonde”:

    “Plutôt que d’envoyer des actions pour naviguer, vous pouvez transmettre l’object historique fourni pour router les composants vers vos actions et naviguer avec lui.”

    Vous pouvez donc envelopper votre composant avec le composant de haut niveau withRouter:

    export default withRouter(connect(null, { actionCreatorName })(ReactComponent));

    qui transmettra l’API d’historique aux accessoires. Vous pouvez donc appeler le créateur de l’action en passant l’historique en tant que paramètre. Par exemple, dans votre ReactComponent:

     onClick={() => { this.props.actionCreatorName( this.props.history, otherParams ); }} 

    Ensuite, dans vos actions / index.js:

     export function actionCreatorName(history, param) { return dispatch => { dispatch({ type: SOME_ACTION, payload: param.data }); history.push("/path"); }; } 

    Nasty question, il m’a fallu beaucoup de temps, mais finalement, je l’ai résolu de cette façon:

    Enveloppez votre conteneur avec withRouter et transmettez l’historique à votre action dans la fonction mapDispatchToProps . En action, utilisez history.push (‘/ url’) pour naviguer.

    Action:

     export function saveData(history, data) { fetch.post('/save', data) .then((response) => { ... history.push('/url'); }) }; 

    Récipient:

     import { withRouter } from 'react-router-dom'; ... const mapDispatchToProps = (dispatch, ownProps) => { return { save: (data) => dispatch(saveData(ownProps.history, data))} }; export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Container)); 

    Ceci est valable pour React Router v4.x.

    this.context.history.push ne fonctionnera pas.

    J’ai réussi à faire fonctionner comme ça:

     static contextTypes = { router: PropTypes.object } handleSubmit(e) { e.preventDefault(); if (this.props.auth.success) { this.context.router.history.push("/some/Path") } } 

    Dans ce cas, vous passez des accessoires à votre thunk. Donc, vous pouvez simplement appeler

     props.history.push('/cart') 

    Si ce n’est pas le cas, vous pouvez toujours transmettre l’historique de votre composant

     export function addProduct(data, history) { return dispatch => { axios.post('/url', data).then((response) => { dispatch({ type: types.AUTH_USER }) history.push('/cart') }) } } 

    J’offre une autre solution au cas où cela serait utile pour quelqu’un d’autre.

    J’ai un fichier history.js lequel je possède les éléments suivants:

     import createHistory from 'history/createBrowserHistory' const history = createHistory() history.pushLater = (...args) => setImmediate(() => history.push(...args)) export default history 

    Ensuite, sur ma racine où je définis mon routeur, j’utilise les éléments suivants:

     import history from '../history' import { Provider } from 'react-redux' import { Router, Route, Switch } from 'react-router-dom' export default class Root extends React.Component { render() { return (    ...    ) } } 

    Enfin, sur mes actions.js j’importe l’Historique et utilise pushLater

     import history from './history' export const login = createAction( ... history.pushLater({ pathname: PATH_REDIRECT_LOGIN }) ...) 

    De cette façon, je peux pousser vers de nouvelles actions après les appels d’API.

    J’espère que cela aide!

    Si vous utilisez Redux, je vous recommande d’utiliser le paquet npm react -router-redux . Il vous permet d’envoyer des actions de navigation dans le magasin Redux.

    Vous devez créer un magasin comme décrit dans leur fichier Lisez-moi .

    Le cas d’utilisation le plus simple:

     import { push } from 'react-router-redux' this.props.dispatch(push('/second page')); 

    Deuxième cas d’utilisation avec conteneur / composant:

    Récipient:

     import { connect } from 'react-redux'; import { push } from 'react-router-redux'; import Form from '../components/Form'; const mapDispatchToProps = dispatch => ({ changeUrl: url => dispatch(push(url)), }); export default connect(null, mapDispatchToProps)(Form); 

    Composant:

     import React, { Component } from 'react'; import PropTypes from 'prop-types'; export default class Form extends Component { handleClick = () => { this.props.changeUrl('/secondPage'); }; render() { return ( 
    Readme file ); } }

    J’ai pu accomplir cela en utilisant bind() . Je voulais cliquer sur un bouton dans index.jsx , publier des données sur le serveur, évaluer la réponse et redirect vers success.jsx . Voici comment j’ai travaillé ça …

    index.jsx :

     import React, { Component } from "react" import { postData } from "../../scripts/request" class Main extends Component { constructor(props) { super(props) this.handleClick = this.handleClick.bind(this) this.postData = postData.bind(this) } handleClick() { const data = { "first_name": "Test", "last_name": "Guy", "email": "test@test.com" } this.postData("person", data) } render() { return ( 
    ) } } export default Main

    request.js :

     import { post } from "./fetch" export const postData = function(url, data) { // post is a fetch() in another script... post(url, data) .then((result) => { if (result.status === "ok") { this.props.history.push("/success") } }) } 

    success.jsx :

     import React from "react" const Success = () => { return ( 
    Hey cool, got it.
    ) } export default Success

    Donc, en liant this à postData dans index.jsx , j’ai pu accéder à this.props.history dans request.js … alors je peux réutiliser cette fonction dans différents composants, je dois juste m’assurer de me souvenir d’inclure this.postData = postData.bind(this) dans le constructor() .

    Utilisez le rappel Cela a fonctionné pour moi!

     export function addProduct(props, callback) { return dispatch => axios.post(`${ROOT_URL}/cart`, props, config) .then(response => { dispatch({ type: types.AUTH_USER }); localStorage.setItem('token', response.data.token); callback(); }); } 

    Dans le composant, il vous suffit d’append le rappel

     this.props.addProduct(props, () => this.props.history.push('/cart')) 

    Voici mon hack (c’est mon fichier racine, avec un peu de redux mélangé – bien que je n’utilise pas react-router-redux ):

     const store = configureStore() const customHistory = createBrowserHistory({ basename: config.urlBasename || '' }) ReactDOM.render(    { window.appHistory = history return (  ) }}/>  , document.getElementById('root') ) 

    Je peux alors utiliser window.appHistory.push() partout où je veux (par exemple, dans les fonctions / thunks / sagas de mon magasin de redux, etc.) J’espérais pouvoir utiliser window.customHistory.push() mais pour une raison react-router n’a jamais semblé mettre à jour même si l’URL a changé. Mais de cette façon, je dispose de l’instance react-router utilise le react-router . Je n’aime pas mettre des choses à l’échelle mondiale, et c’est l’une des rares choses que je ferais avec. Mais c’est mieux que toute autre alternative que j’ai vue à l’OMI.

    vous pouvez l’utiliser comme ça comme je le fais pour la connexion et les choses différentes manny

     class Login extends Component { constructor(props){ super(props); this.login=this.login.bind(this) } login(){ this.props.history.push('/dashboard'); } render() { return ( 
    )
     /*Step 1*/ myFunction(){ this.props.history.push("/home"); } /**/