Comment obtenir l'historique sur React-Router v4?

102

J'ai un petit problème lors de la migration de React-Router v3 vers v4. dans la v3, j'ai pu le faire n'importe où:

import { browserHistory } from 'react-router';
browserHistory.push('/some/path');

Comment puis-je y parvenir dans la v4.

Je sais que je pourrais utiliser, le hoc withRouter, le contexte de réaction ou les accessoires de routeur d'événements lorsque vous êtes dans un composant. mais ce n'est pas le cas pour moi.

Je recherche l'équivalence de NavigatingOutsideOfComponents en v4

storm_buster
la source
1
Merci @Chris, mais comme je l'ai dit, je ne suis pas dans Component.
storm_buster
@Chris dans une classe utilitaire, veuillez consulter github.com/ReactTraining/react-router/blob/master/docs/guides/… , cela aurait pu être un redux middlewarere ou autre chose
storm_buster
façon simple stackoverflow.com/a/53916596/3966458
Saahithyan Vigneswaran
J'ai fini par utiliser le BrowserRouter comme composant racine. De cette façon, je pourrais utiliser le composant App withRouter. Pas exactement ce que vous avez demandé mais j'ai les mêmes exigences et cela me suffit.
The Fool

Réponses:

181

Vous avez juste besoin d'un module qui exporte un historyobjet. Ensuite, vous importeriez cet objet tout au long de votre projet.

// history.js
import { createBrowserHistory } from 'history'

export default createBrowserHistory({
  /* pass a configuration object here if needed */
})

Ensuite, au lieu d'utiliser l'un des routeurs intégrés, vous utiliseriez le <Router>composant.

// index.js
import { Router } from 'react-router-dom'
import history from './history'
import App from './App'

ReactDOM.render((
  <Router history={history}>
    <App />
  </Router>
), holder)
// some-other-file.js
import history from './history'
history.push('/go-here')
Paul S
la source
1
Merci beaucoup! Pour le moment, en utilisant react-router4, j'ai dû utiliser cette importation dans history.js à la place: import createBrowserHistory de 'history / createBrowserHistory';
peter.bartos
3
Ça a marché pour moi quand je mets history = {history} dans Route et que je passe comme un accessoire
Nath Paiva
1
nous pouvons utiliser withHistory et obtenir l'historique dans les accessoires plutôt que de créer un fichier séparé. cette solution n'a pas fonctionné pour moi avec redux.
Zeel Shah
4
Importez createHashHistorysi vous utilisiez HashRouter.
David Harkness
2
@HassanAzzam Vous utilisez probablement react-router V5, et cette réponse fonctionne pour V4, pas V5. J'ai actuellement le même défi et je cherche partout, mais je n'arrive pas à le faire fonctionner. history.push en dehors du composant fonctionne, mais ne clique plus sur le lien.
Waterlink
71

Cela marche! https://reacttraining.com/react-router/web/api/withRouter

import { withRouter } from 'react-router-dom';

class MyComponent extends React.Component {
  render () {
    this.props.history;
  }
}

withRouter(MyComponent);
Justin Yueh
la source
27
tant que vous êtes dans un composant. Je ne suis pas dans un composant
storm_buster
1
Merci, c'est le moyen le plus simple et le plus simple de créer un lien vers un autre itinéraire à partir d'un composant. J'ajouterais simplement que vous devez faire this.props.history.push('/some_route');pour que cela fonctionne.
dannytenaglias
1
@storm_buster const Component = props => {... // stuff}et export default withRouter(Component)travaille pour moi sur un composant sans état
Karl Taylor
10

De même que la réponse acceptée, vous pouvez utiliser reactet react-routerlui - même pour vous fournir un historyobjet que vous pouvez définir dans un fichier, puis exporter.

history.js

import React from 'react';
import { withRouter } from 'react-router';

// variable which will point to react-router history
let globalHistory = null;

// component which we will mount on top of the app
class Spy extends React.Component {
  constructor(props) {
    super(props)
    globalHistory = props.history; 
  }

  componentDidUpdate() {
    globalHistory = this.props.history;
  }

  render(){
    return null;
  }
}

export const GlobalHistory = withRouter(Spy);

// export react-router history
export default function getHistory() {    
  return globalHistory;
}

Vous importez ensuite le composant et le montez pour initialiser la variable d'historique:

import { BrowserRouter } from 'react-router-dom';
import { GlobalHistory } from './history';

function render() {
  ReactDOM.render(
    <BrowserRouter>
        <div>
            <GlobalHistory />
            //.....
        </div>
    </BrowserRouter>
    document.getElementById('app'),
  );
}

Et puis vous pouvez simplement importer dans votre application une fois qu'elle a été montée:

import getHistory from './history'; 

export const goToPage = () => (dispatch) => {
  dispatch({ type: GO_TO_SUCCESS_PAGE });
  getHistory().push('/success'); // at this point component probably has been mounted and we can safely get `history`
};

J'ai même créé un package npm qui fait exactement cela.

Tomasz Mularczyk
la source
À partir de reactjs 16.9, cette solution crachera un avertissement d'obsolescence sur componentWillMount et componentWillReceiveProps.
ian
1
@ian true, corrigé ça
Tomasz Mularczyk
5

Si vous utilisez redux et redux-thunk, la meilleure solution sera d'utiliser react-router-redux

// then, in redux actions for example
import { push } from 'react-router-redux'

dispatch(push('/some/path'))

Il est important de consulter la documentation pour effectuer certaines configurations.

Arnold Gandarillas
la source
1
Je suis venu ici dans l'espoir de trouver cette solution exacte, merci
vapurrmaid
4

En vous basant sur cette réponse si vous avez besoin d'un objet d'historique uniquement pour accéder à un autre composant:

import { useHistory } from "react-router-dom";

function HomeButton() {
  const history = useHistory();

  function handleClick() {
    history.push("/home");
  }

  return (
    <button type="button" onClick={handleClick}>
      Go home
    </button>
  );
}
Konrad Grzyb
la source
FAUX, vous êtes dans un composant. voir // some-other-file.js de la réponse acceptée
storm_buster
0

Dans App.js

 import {useHistory } from "react-router-dom";

 const TheContext = React.createContext(null);

 const App = () => {
   const history = useHistory();

   <TheContext.Provider value={{ history, user }}>

    <Switch>
        <Route exact path="/" render={(props) => <Home {...props} />} />
        <Route
          exact
          path="/sign-up"
          render={(props) => <SignUp {...props} setUser={setUser} />}
        /> ...

Puis dans un composant enfant:

const Welcome = () => {
    
    const {user, history} = React.useContext(TheContext); 
    ....
Squirrl
la source
-2

Dans le cas spécifique de react-router, l'utilisation contextest un scénario valable, par ex.

class MyComponent extends React.Component {
  props: PropsType;

  static contextTypes = {
    router: PropTypes.object
  };

  render () {
    this.context.router;
  }
}

Vous pouvez accéder à une instance de l'historique via le contexte du routeur, par exemple this.context.router.history.

Gajus
la source
La question est spécifiquement de savoir quand en dehors d'un composant, donc this.context n'est pas disponible en option:> "Je sais que je pourrais utiliser, le hoc withRouter, le contexte de réaction ou les accessoires de routeur d'événements lorsque vous êtes dans un composant. Mais ce n'est pas le cas pour moi. "
SunshinyDoyle