How to get history on react-router v4?

ReactjsReact Router

Reactjs Problem Overview


I having some little issue migrating from React-Router v3 to v4. in v3 I was able to do this anywhere:

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

How do I achieve this in v4.

I know that I could use, the hoc withRouter, react context, or event router props when you are in a Component. but it is not the case for me.

I am looking for the equivalence of NavigatingOutsideOfComponents in v4

Reactjs Solutions


Solution 1 - Reactjs

You just need to have a module that exports a history object. Then you would import that object throughout your project.

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

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

Then, instead of using one of the built-in routers, you would use the <Router> component.

// 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')

Solution 2 - Reactjs

This works! 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);

Solution 3 - Reactjs

Basing on this answer if you need history object only in order to navigate to other component:

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>
  );
}

Solution 4 - Reactjs

Similiary to accepted answer what you could do is use react and react-router itself to provide you history object which you can scope in a file and then export.

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;
}

You later then import Component and mount to initialize history variable:

import { BrowserRouter } from 'react-router-dom';
import { GlobalHistory } from './history';
 
function render() {
  ReactDOM.render(
    <BrowserRouter>
        <div>
            <GlobalHistory />
            //.....
        </div>
    </BrowserRouter>
    document.getElementById('app'),
  );
}

And then you can just import in your app when it has been mounted:

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`
};

I even made and npm package that does just that.

Solution 5 - Reactjs

If you are using redux and redux-thunk the best solution will be using react-router-redux

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

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

> It's important to see the docs to do some configurations.

Solution 6 - Reactjs

In 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} />}
        /> ...


Then in a child component :

const Welcome = () => {
    
    const {user, history} = React.useContext(TheContext); 
    ....

Solution 7 - Reactjs

In the specific case of react-router, using context is a valid case scenario, e.g.

class MyComponent extends React.Component {
  props: PropsType;

  static contextTypes = {
    router: PropTypes.object
  };

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

You can access an instance of the history via the router context, e.g. this.context.router.history.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionstorm_busterView Question on Stackoverflow
Solution 1 - ReactjsPaul SView Answer on Stackoverflow
Solution 2 - ReactjsJustin YuehView Answer on Stackoverflow
Solution 3 - ReactjsKonrad GrzybView Answer on Stackoverflow
Solution 4 - ReactjsTomasz MularczykView Answer on Stackoverflow
Solution 5 - ReactjsArnold GandarillasView Answer on Stackoverflow
Solution 6 - ReactjsSquirrlView Answer on Stackoverflow
Solution 7 - ReactjsGajusView Answer on Stackoverflow