In order to start building relevant web applications with React, we must have a way of showing different components based on the url visited by the user, otherwise known as routing.
Traditionally routing has been handled by the backend, so each route change meant a full page reload, a new HTML basically taking the place of the old one. With client side routing we can work our way around this, changing the components (pages) on the fly and changing the url (based on the strategy used) while keeping the same root HTML in place.
There are multiple libraries that are handling routing functionalities in React and there's no official library built by the core team, as there is the case of Vue.js. However, react-router is pretty much the standard approach today. Other notable libraries are: reach-router - accessible first routing library and router5(https://router5.js.org/).
There are two main options for configuring a router, BrowserRouter
and HashRouter
.
BrowserRouter relies on the HistoryAPI capabilities introduced in HTML5, on pushState, popState and replaceState. This is very convenient because the user doesn't see any difference compared to traditionally server rendered applications. For them, the url changes, the page changes. The only perceivable difference is in speed, because they don't get a new page load.
HashRouter relies on the hash part (ex: example.com/#about) of the url and can be convenient when you have a client application mounted inside a more complex server rendered application and you don't want to change the base url for that application.
Here is the most basic setup for react-router involving 3 pages and using the browser history:
<BrowserRouter>
<div>
<header>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
<Link to="/contact">Contact</Link>
</header>
<Route path="/" exact component={Home} />
<Route path="/about" component={About} />
<Route path="/contact" component={Contact} />
</div>
</BrowserRouter>
BrowserRouter
can easily we swapped with HashRouter
to enable hash navigation instead. the Link
component simply renders an anchor tag which changes the url when clicked. However, this does not behave as a regular anchor tag and does not trigger a full page reload.
Complete solution in codesandbox
The Route
component works on a very simple principle: If the url matches, the component is rendered in place. There are multiple props that you can use on a Route
, but most importantly you would want to use exact: true
or simply exact
as an attribute. When exact
is true, the url match is done using the string equality operation. When exact
is false, which is the default value, the match is done using indexOf
. This means that if you have two Routes defined next to each other, one with the path /java
and one with /java/script
, both components will be rendered one after another when the user ends on /java
.
There's also a <Switch>
tag which can be used, also part of react-router
which forces a single component to be rendered at a time. This is useful when building a complex page routing, but you must be careful with the order of the routes, or you risk having a general route take precedence over a more specific one.
There are cases where you want the url to have a dynamic part (ex: an id, a permalink, a category). For those situations, the paths can be matched against dynamic routes:
<Route path="/food/:foodType" component={Restaurant} />
At this point, any url starting with /food
will match with this route: /food/pizza, /food/icecream.
Subsequently, when the <Restaurant>
component will mount, it will receive the following props:
this.props.location
-> reference to the browser location objectthis.props.history
-> reference to the browser history objectthis.props.match
-> an object with the result of the route match, that among others has the params from the dynamic url
Hence, if you want to access the dynamic :foodType
param, you would use: this.props.match.params.foodType
. You can check out this full example on codesandbox.
Another useful scenario is when you want a certain url to be redirected to another one, or you want to redirect somewhere based on a user action (ex: login). In those cases, you can use the <Redirect>
component. When a <Redirect>
is rendered, it immediately uses the history API to change the url to the specified location. When <Redirect>
is specified in a list of routes, you need to send the from
prop, for react-router to know when the redirect should happen.
Check this example of using a Redirect component.
References