5

With the previous react-router I was able to do this:

import {browserHistory} from 'react-router';

from my actionCreators file and I could do something like this:

...some async action completed (for example, user logged in successfully)..
browserHistory.push('/dashboard');

But with the new react-router-dom (v4) it seems like I can no longer import browserHistory just like that and that the only way to access the history object is from a React components props

this.props.history

What would be a way to redirect my user to a new page after an async redux action has completed using react-router-dom?

Alejandro Figueroa
  • 419
  • 1
  • 4
  • 14

2 Answers2

5

withRouter is what you're looking for.

"You can get access to the history object’s properties and the closest 's match via the withRouter higher-order component."

import React, { PropTypes } from 'react'
import { withRouter } from 'react-router'

// A simple component that shows the pathname of the current location
class ShowTheLocation extends React.Component {
  static propTypes = {
    match: PropTypes.object.isRequired,
    location: PropTypes.object.isRequired,
    history: PropTypes.object.isRequired
  }

  render() {
    const { match, location, history } = this.props

    return (
      <div>You are now at {location.pathname}</div>
    )
  }
}

// Create a new component that is "connected" (to borrow redux
// terminology) to the router.
const ShowTheLocationWithRouter = withRouter(ShowTheLocation)
Tyler McGinnis
  • 34,836
  • 16
  • 72
  • 77
  • But what if I want to use the history object from inside a redux-thunk or redux-saga? Not inside a react component – Alejandro Figueroa Apr 06 '17 at 13:09
  • So at the end what I did was to have a redux state property that is changed to be true (lets say its called "userLogged") when the async action is completed. I wrapped my container component inside "withRouter" and in the "componentWillReceiveProps" method I check if the "userLogged" property is true and then I use the history object to push the new route. – Alejandro Figueroa Apr 06 '17 at 20:19
  • 1
    Actually I found a way to do what I wanted on the react router website examples. It seems like you can return a component on the render() method, so instead of check if "userLogged" is true inside "componentWillReceiveProps" you could just check "userLogged" prop inside the render() method if is true do something like this: if (userLogged) return Here is the link to the example: https://reacttraining.com/react-router/web/example/auth-workflow – Alejandro Figueroa Apr 07 '17 at 02:14
  • 7
    being able to import browserHistory and do browserHistory.push('whereIWantToGo') was infinitely simpler and straightforward. Whatever happened between v3 and v4 seems like an overengineering – arcom Jul 29 '17 at 16:27
0

You can trigger a navigation of your react-router from anywhere in your code, including from redux middleware, by storing a reference to your router in a module.

  1. Create a module RouterAccessor that holds an instance to the router.
// In RouterAccessor.ts
import type { Router as RemixRouter } from "@remix-run/router"

let routerInstance: RemixRouter | undefined

export function setRouter(router: RemixRouter) {
  if (routerInstance !== undefined) throw new Error("Router already set")
  routerInstance = router
}
// You could also export only the navigate method.
export function getRouter() {
  return routerInstance
}
  1. After creating the router in the App module using createBrowserRouter, save the instance in RouterAccessor.
// In App.tsx
import { createBrowserRouter, RouterProvider } from "react-router-dom"
import * as RouterAccessor from './RouterAccessor'

const router = createBrowserRouter(...)

// Store the router instance so any module can use it.
RouterAccessor.setRouter(router)

... <RouterProvider router={router} /> ...
  1. Access the router instance from anywhere in your app.
// In YourMiddleware.ts
import * as RouterAccessor from '../RouterAccessor'

RouterAccessor.getRouter().navigate('/contacts/1')
David
  • 355
  • 1
  • 9