I have just replaced react-router
from v3 to v4.
But I am not sure how to programmatically navigate in the member function of a Component
.
i.e in handleClick()
function I want to navigate to /path/some/where
after processing some data.
I used to do that by:
import { browserHistory } from 'react-router'
browserHistory.push('/path/some/where')
But I can't find such interfaces in v4.
How can I navigate using v4?
Best Answer
If you are targeting browser environments, you need to use
react-router-dom
package, instead ofreact-router
. They are following the same approach as React did, in order to separate the core, (react
) and the platform specific code, (react-dom
,react-native
) with the subtle difference that you don't need to install two separate packages, so the environment packages contain everything you need. You can add it to your project as:yarn add react-router-dom
or
npm i react-router-dom
The first thing you need to do is to provide a
<BrowserRouter>
as the top most parent component in your application.<BrowserRouter>
uses the HTML5history
API and manages it for you, so you don't have to worry about instantiating it yourself and passing it down to the<BrowserRouter>
component as a prop (as you needed to do in previous versions).In V4, for navigating programatically you need to access the
history
object, which is available through Reactcontext
, as long as you have a<BrowserRouter>
provider component as the top most parent in your application. The library exposes through context therouter
object, that itself containshistory
as a property. Thehistory
interface offers several navigation methods, such aspush
,replace
andgoBack
, among others. You can check the whole list of properties and methods here.Important Note to Redux/Mobx users
If you are using redux or mobx as your state management library in your application, you may have come across issues with components that should be location-aware but are not re-rendered after triggering an URL updateThat's happening because
react-router
passeslocation
to components using the context model.The 2 approaches for solving this are:
<Route />
. The currentlocation
object is one of the props that a<Route>
passes to the component it renderswithRouter
higher-order component, that in fact has the same effect and injectslocation
as a propSetting that aside, there are four ways to navigate programatically, ordered by recommendation:
1.- Using a
It promotes a declarative style. Prior to v4,<Route>
Component<Route />
components were placed at the top of your component hierarchy, having to think of your routes structure beforehand. However, now you can have<Route>
components anywhere in your tree, allowing you to have a finer control for conditionally rendering depending on the URL.Route
injectsmatch
,location
andhistory
as props into your component. The navigation methods (such aspush
,replace
,goBack
...) are available as properties of thehistory
object.There are 3 ways to render something with a
Route
, by using eithercomponent
,render
orchildren
props, but don't use more than one in the sameRoute
. The choice depends on the use case, but basically the first two options will only render your component if thepath
matches the url location, whereas withchildren
the component will be rendered whether the path matches the location or not (useful for adjusting the UI based on URL matching).If you want to customise your component rendering output, you need to wrap your component in a function and use the
render
option, in order to pass to your component any other props you desire, apart frommatch
,location
andhistory
. An example to illustrate:2.- Using
withRouter
HoCThis higher order component will inject the same props as
Route
. However, it carries along the limitation that you can have only 1 HoC per file.3.- Using a
Rendering aRedirect
component<Redirect>
will navigate to a new location. But keep in mind that, by default, the current location is replaced by the new one, like server-side redirects (HTTP 3xx). The new location is provided byto
prop, that can be a string (URL to redirect to) or alocation
object. If you want to push a new entry onto the history instead, pass apush
prop as well and set it totrue
4.- Accessing
A bit discouraged because context is still an experimental API and it is likely to break/change in future releases of Reactrouter
manually through contextNeedless to say there are also other Router components that are meant to be for non browser ecosystems, such as
<NativeRouter>
that replicates a navigation stack in memory and targets React Native platform, available throughreact-router-native
package.For any further reference, don't hesitate to take a look at the official docs. There is also a video made by one of the co-authors of the library that provides a pretty cool introduction to react-router v4, highlighting some of the major changes.