Learning React Router
React Router (DOM) allows developers to create multiple-page projects with React through supporting using components as ‘pages’ for different URL routes.
Router Hooks
While setting specific and known routes can be useful when using React Router, there might also be the case where API design is needed and dynamic routes could be used to pass along URI parameters. For situations like these, React Router provides a hook: useParams().
useParams()
Consider the following updated code block from the “index.js” file:
<BrowserRouter>
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/user/:id">
<User />
</Route>
<Route path="/">
<App />
</Route>
</Switch>
</BrowserRouter>
The route for <User> has been changed to “/user/:id”. An additional URL parameter, id, was introduced. For whatever is supplied in there from a requesting client, it will appear as part of the params of the component.
To access any URL parameters, the hook useParams() can be used.
Consider the following updated <User> function component:
import React from "react";
import { Link, useParams } from 'react-router-dom';
function User() {
const {id} = useParams();
return(
<div>
<h1>User page</h1>
<Link to="/about">About</Link>
<p>Current id is {id}</p>
</div>
);
}
export default User;
If specified as part of a <Route> component, and accessed via useParams() via its hook, different URL parameters can be passed to components. The resulting object literal will contain all key-value pairs created from the URL parameters of the requested route as defined within the central <Switch>.
useRouteMatch()
If useParams() is used by changing the central routing to add new URI parameters, the function useRouteMatch() is used for changing individual class and function components and testing if additional URI components have been passed to it.
Consider the following revised <User> function component:
import React from "react";
import { Link, useRouteMatch } from 'react-router-dom';
function User() {
const uriParameters = useRouteMatch("/user/:id");
let result;
// uriParameters will be null if route does not match
if(uriParameters === null) {
result =
<div>
<h1>User page</h1>
<Link to="/about">About</Link>
</div>;
} else {
// uriParameters will contain 'params' with 'id'
result =
<div>
<h1>User page</h1>
<Link to="/about">About</Link>
<p>Current id is {uriParameters.params.id}</p>
</div>;
}
return(result);
}
export default User;
In the above code, if the route “/user” is accessed, the client will receive one set of output. If a route of “/user/:id” where “id” is some value is accessed, the client will receive different output, returning the “id” passed to it.
The updated code for “index.js” looks as it does before the useParams() example as well:
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Switch, Route } from 'react-router-dom';
import App from './App';
import About from './components/about';
import User from './components/user';
const routes =
<BrowserRouter>
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/user">
<User />
</Route>
<Route path="/">
<App />
</Route>
</Switch>
</BrowserRouter>;
ReactDOM.render(routes, document.getElementById('root'));
useParams() or useRouteMatch()?
The choice between the hooks has more to do with the design patterns enacted in the particular React project they are used in than anything else.
The hook useRouteMatch() follows a design pattern of working with individual components to augment their ability to react to URI parameters.
The hook useParams(), on the other hand, works with the existing <Route> component structure and requires updating the central routing AND the component to work correctly.
Very generally, useParams() makes the most sense for longer-term API changes where the API URI structure is known and unlikely to change over time. useRouteMatch() often makes more sense for projects with incoming API changes that allows a component to react to different URI parameters without changing the central routing paths already in use.