Understanding the Basics of Routing in React (pt 1)
When you’re building a React application, you’ll reach a point where you’ll need to create the ability to navigate to other parts of your app. This can be done by 1) clicking on a button, link, image, or some other element on the DOM. OR 2) Changing the URL in the browser.
However, both options require the use of a common routing library, React Router. This library comes with its core library along with two tools: react-router-dom (for web apps) and react-router-native (for mobile apps). For the purposes of this blog, I will be discussing react-router-dom.
Installation
To get started, you can install the library by running:
npm install --save react-router-dom
BrowserRouter
Within the React Router package, you will find the BrowserRouter
, which is made for applications with a dynamic server. Recall that “dynamic server” refers to an application with a server that updates. In other words, if your server can update anything in the database (create, update, delete, etc.), then you have a dynamic server. If you’re creating a static application, you’d want to use the HashRouter
, but we’ll be discussing the BrowserRouter
here.
To set up, you’ll need to give Router
, the alias for BrowserRouter
, only one child. See below in our index.js file, where the <App />
component is the only child of the Router
.
import { BrowserRouter as Router } from 'react-router-dom'ReactDOM.render(
<Router>
<App />
</Router>, document.getElementById('root')
);
This signals to React that all routing will occur within the <App />
component.
Routes
Next, are the <Route />
components, which will each contain a path pointing to the correct UI. But how does a <Route />
component contain a path? To understand exactly how a route is matched it’s important to take a closer look at what Router
gives us.
Router
uses the HTML5 history API, which creates a history object, and that history object contains a property called location, which points to its own object. Inside that location object, you’ll find:
{ pathname, search, hash, state }
So, Router
knows the current location of the app and when it changes. That’s why we wrap all the other <Route />
components inside the Router
, so they have access to the history object, and thereby, the app’s location.
To route to a path, you specify the desired path inside a <Route />
.
<Route path='/mushrooms' />
The path
is actually a prop that indicates the pathname that the route should match. You can also limit the match using exact
, so that it only matches the path and ignores parameters, such as ‘/mushrooms/3’
.
<Route exact path='/mushrooms' />
Now that you’ve matched a path, you should specify which component to render. For that, you can use either the component or render props.
Component Prop
After indicating the path, you can use the component prop to specify what should render in the UI.
<Route path=”/mushrooms” component={Mushrooms} />
But this can be limiting if you want to pass props to the component. For example, if I fetch all mushrooms in my <App />
component, I will need to pass down the array of mushrooms in state to my <Mushrooms />
component. For that, we can use the render prop.
Render Prop
If I have an array of mushrooms in state that I’d like to pass down as a prop to another component, I can use:
<Route
path=”/mushrooms”
render={() => <Mushrooms allMush={this.state.mushrooms}
/>
The render prop takes in a function, which returns a component (or React element) when the app’s location matches the route’s path.
A Quick Word on Switch
If you have a list of <Route />
components, you may find it convenient to only match the first in the list that matches your path. For that, we can use the <Switch />
component, which wraps multiple <Route />
components and matches only the first path that matches the location. This is especially useful if you have nested routes like below:
<Switch> <Route
path='/mushrooms/:id'
render={ (routerProps) => {
const mushId = parseInt(routerProps.match.params.id)
return <MushShowPage {...routerProps} mushId={mushId} />}
}
/>
<Route
path='/mushrooms'
render={ (history) => <MushroomContainer />}
/>
</Switch>
In pt 2, I’ll discuss how to use the <Link />
component to route.
References: