Fundamentals of Routing in React
In React, routing is the ability to move between different parts of an application when a user enters a URL and triggers an event (e.g., clicking an element or submitting a form). To utilize routing, you will need to install the React-Router library. It is important to note that this library has three variants:
- react-router: the core library
- react-router-dom: a version of the core library meant to be used for web applications
- react-router-native: a version of the core library meant to be used with react native for the development of Android and iOS applications
Most often, there is no need to install the core library. Since I have been focusing on web development in Flatiron School’s Software Engineering Bootcamp, I will choose to explore react-router-dom. This library can be installed by running npm install — save react-router-dom in the project directory.
This package includes BrowserRouter, HashRouter, and MemoryRouter; because I am using a dynamic server that knows how to handle any type of URL, the BrowserRouter is a good fit. It is important to note that all routers, including the BrowserRouter, expect to receive one child. Therefore, we will pass our top level component (in my case — <App/>) to the router as seen below. Once I give BrowserRouter <App/> as a child, routing can happen anywhere in the <App/> component.
Each router creates a history object that is used to keep track of the current location and re-render the application whenever that location changes. As a result, the other React Router components rely on this history object and need to be rendered inside a router.
The BrowserRouter uses the HTML5history API to keep the user interface in sync with the URL in the browser’s address bar. The history object created by the Router contains a number of properties, most notably being location whose value is also an object.
When <App /> is rendered in the browser, under the React components in the DevTools, you should be able to see this history object. The location object properties are derived from the application URL.
The <Route /> component renders the appropriate user interface when the current location matches the route’s path. The path is a prop on the <Route /> component that describes the pathname that the route should match. For example: <Route path=“/users” />. This route is matched when the pathname is /users or any path that starts with /user (e.g., /users/:id). If you only want your path to strictly match /users, then the <Route /> component must accept an exact prop (e.g., <Route exact path=”/users” />). This ensures that only the pathname that exactly matches the current location is rendered. The <Route /> component provides three props that can be used to determine which component to render:
- Component
- Render
- Child
Component Prop
The component prop defines the React element that will be returned by the Route when the path is matched. An example includes: <Route exact path=“/users” component={users} />.
Render Prop
The render prop provides the ability for inline rendering and passing down of props to the element. This prop expects a function that returns a React element when the current location matches the route’s path. An example includes: <Route exact path=“/users” render={() => (<div>All Users</div>)} />.
Children Prop
The children prop also expects a function that returns a React element. The element defined but the child prop is returned for all paths irrespective of current location. An example includes,<Route children={props => <Users {…props}/>}/>. In this case, the users component is always rendered.
Switch
The react-router library also contains a <Switch/> component that is used to wrap multiple <Route/> components. <Switch /> functions conditionally and will only render a route if it matches the pathname. In the example below, we want to navigate to /users/5. By using the <Switch /> component, we will just render the single user (instead of the index).
<Switch>
<Route
path=”/users/5"
render={() => (<div>Sidney</div>)}
/>
<Route
path=”/users”
render={() => (<div><em>All Users</em></div>)}
/>
</Switch>
Note: Our most specific paths must go at the top of <Switch /> component as <Switch /> renders the first path that matches the current location. In other words, /users would be matched when /users/5 is entered into the browser’s address bar.
NavLink
In addition to <Switch />, the react-router package also contains a <NavLink /> component that is used to navigate to different parts of the application by way of hyperlinks. Using this component alters the UI without reloading the page thus maintaining a more positive user experience. When clicked, it also updated the URL.
The Users component contains links to individual show pages for users. The <NavLink /> component uses to as a prop to define the location for the application navigate to. This prop can be a string or a location object. In the example above, clicking on the user’s image triggers a UI change and updates the URL in the address bar to reflect rendering a single user.
Nested Routes
When the router’s path and location are matched a match object is created. The object contains information about the URL and the path. This information can be accessed as properties on the match object. The match object’s properties include:
- url: A string that returns the matched part of the URL
- path: A string that returns the route’s path
- isExact: A boolean that returns true if the match was exact
- params: An object containing key-value pairs that were matched by the Path-To-RegExp package.
An example of a nested route is as follows: