What is routing?
Routing is the process by which a web application uses the current browser URL (Uniform Resource Locator) to determine what content to show a user.
For example, a user visiting wikipedia’s /wiki/Node.js page would expect to see something different from the /wiki/React_(JavaScript_library) page.
By organizing an application’s content and displaying only what the user has requested to see, routing allows for rich, engaging, and clear user experiences.
- Every URL is essentially a request for some resource and each component of the URL serves to specify which resource is desired. URLs consist of several components, some of which are mandatory and some of which are optional:
- The scheme (eg. HTTP, HTTPS, mailto, etc), which specifies what protocol should be used to access the resource.
- The domain (eg. codecademy.com), which specifies the website that hosts the resource. The domain serves as the entry point for your application.
- The path (eg. /articles), which identifies the specific resource or page to be loaded and displayed to the user. This is where routing begins!
- The optional query string (eg. ?search=node), which appears after a ‘?’ and assigns values to parameters. Common uses of query strings include search parameters and filters.
Depending on the kind of application you build, there are different ways to handle the requests coming into your server. A popular back-end solution is to use the Express routing framework.
Installing React Router
In order to use React Router, you will need to include the react-router-dom package (the version of React Router built specifically for web browsers) in your project by using npm like so:
npm install --save react-router-dom@5.2.0
Once you have added react-router-dom to your project, you can import one of its router components to add routing to your project.
React Router provides several router components however the most common one is the BrowserRouter.
For the sake of simplicity and readability, it is common to alias BrowserRouter as Router when importing, like so:
import { BrowserRouter as Router} from ‘react-router-dom’
Rendering A
In the React Router paradigm, the different views of your application, also called routes, along with the Router itself, are just React components. To include them in your application, you will need to render them.
The first step is to render a Router component as the top-level component in your application.
import { BrowserRouter as Router } from 'react-router-dom';
export default function App () {
return (
<Router>
{/* Application views are rendered here */
</Router>
)
}
Making Router the top-level component prevents URL changes from causing the page to** reload.**
Instead, URL changes will allow the Router to determine which of its child components to render while passing along information about the current URL’s path as props.
Basic Routing with
With the Router component in place, we can begin defining the different views, or routes, that our application will render for various URL paths.
For example, we might want to render an About component for the /about path and a SignUp component for the /sign-up path.
To do this, we must use the Route component provided by the react-router-dom package. This component can be imported alongside the BrowserRouter like so:
import { BrowserRouter as Router, Route } from `react-router-dom`
The Route component is designed to render (or not render) a component based on the current URL path. Each Route component should:
- be rendered inside a Router.
- have a path prop indicating the URL path that will cause the route to render.
- wrap the component that we want to display in the event that the path prop matches. For example, the following Route renders the About component when the URL path matches '/about':
<Router>
<Route path='/about'>
<About />
</Route>
</Router>
If your router includes a Route with no path prop, then that route will always match and render. You can leverage this fact to make your application render components that you want your user to see regardless of the current route, such as sidebars and navigation bars.
<Router>
{/* Renders when the URL matches '/about' */
<Route path='/about'>
<About />
</Route>
{/* Always renders */}
<Route>
<Sidebar />
</Route>
</Router>
Whereas other routing paradigms are static (eg. routes are predefined prior to and separate from the process of rendering), React Router’s philosophy is declarative and dynamic.
This means that routes come into being when they are rendered. While this might seem more complicated than configuring our routes statically, it’s also more flexible.
Dynamic Routes
So far, all the routes we’ve covered have been static, which means they match a single unique path. This works for certain types of routes, but not all.
For example, imagine in a tech news site where every article is accessible at the path '/articles/' + someTitle where someTitle is different for each article.
Specifying a unique route for every article would not only be verbose and time-consuming, it would require an impractical amount of maintenance should the path structure ever change.
Instead, we would rather express the pattern at a high level with a single route that can match any path of the form '/articles/' + someTitle and still know which article to render. React Router allows us to do this by using URL parameters to create dynamic routes.
URL parameters are dynamic segments of a URL that act as placeholders for more specific resources the URL is meant to display. They appear in a dynamic route as a colon (:) followed by a variable name, like so:
<Route path='/articles/:title'>
<Article />
</Route>
Let’s break down this short:
- In this example, the path '/articles/:title' contains the URL parameter :title.
- This means that when the user navigates to pages such as '/articles/what-is-react' or '/articles/html-and-css', the component will render.
- When the Article component is rendered in this way, it can access the actual value of that :title URL parameter (what-is-react or html-and-css) to determine which article to display (more on this in the next exercise).
A single route can even have multiple parameters (eg. '/articles/:title/comments/:commentId') or none (eg. '/articles').
To make a URL parameter optional, you can append a '?' to the end of the URL parameter’s name (eg. '/articles/:title?')
In this case, the child component of the Route will render when the URL matches either /articles/what-is-react or just /articles.
useParams
It is common to use the value of URL parameters to determine what is displayed in the component that a dynamic route renders. For example, the Article component might need to display the title of the current article.
React Router provides a hook, useParams(), for accessing the value of URL parameters. When called, useParams() returns an object that maps the names of URL Parameters to their values in the current URL.
For example, consider the Articles component below which is rendered when by a route with the dynamic URL '/articles/:title'. Suppose the user visits /articles/objects:
import { Link, useParams } from 'react-router-dom';
// Rendered when the user visits '/articles/objects'
export default function Article() {
let { title } = useParams();
// title will be equal to the string 'objects'
// The title will be rendered in the <h1>
return (
<article>
<h1>{title}</h1>
// ...
</article>
);
}
and exact
By design, a Router will render all the Routes whose paths match the current URL. This allows us to compose layouts in which multiple components should appear or disappear based on the current URL (for example, an application in which the sidebar and main display respond to changes in the current URL). But sometimes, this design choice can produce unintended results.
Consider the following (relatively common) setup:
<Router>
<div>
<Route path='/articles/new'>
<NewArticle />
</Route>
<Route path='/articles/:title'>
<Article />
</Route>
<Route path='/articles'>
<Articles />
</Route>
</div>
</Router>
What should happen when the user navigates to 'articles/new'? The NewArticle component should appear, right?
What actually happens is that ALL routes match:
- /articles/new matches exactly
- /articles/:title will match new to the URL parameter :title
- /articles will match because both begin with /articles.
Because all routes match, the application will render the
NewArticle, Article, and Articles components simultaneously.
React Router provides several mechanisms for preventing this sort of unintended rendering. The first is the Switch component:
import { Switch } from 'react-router-dom';
When wrapped around a collection of routes, Switch will render the first of its child routes whose path prop matches the current URL.
<Switch>
<div>
<Route path='/articles/new'>
<NewArticle />
</Route>
<Route path='/articles/:title'>
<Article />
</Route>
<Route path='/articles'>
<Articles />
</Route>
</div>
</Switch>
Because the Switch checks routes sequentially, the order in which Routes are rendered matters. Consider a similar example but with the order of the routes reversed:
<Switch>
<div>
<Route path='/articles/:title'>
<Article />
</Route>
<Route path='/articles/new'>
<NewArticle />
</Route>
<Route path='/articles'>
<Articles />
</Route>
</div>
</Switch>
Now imagine that a user navigates to '/articles/new'. The Switch renders the first route with a matching path, '/articles/new' matches '/articles/:title', since :title is a dynamic segment. With the routes listed in this order, the NewArticle component will never render. In general, you can avoid this problem by listing routes from most- to least-specific.
Sometimes you may want to leverage React Router’s composability and render multiple routes simultaneously (this would prevent you from using a Switch component) while also ensuring your router distinguishes between static paths and paths including URL parameters. Consider the following example:
<Router>
<div>
<Route path='/'>
<Home />
</Route>
<Route path='/sign-up'>
<SignUp />
</Route>
</div>
</Router>
Any path will match first route, so the the Home component will be rendered whether the user is at '/' or '/sign-up'. This might be ideal behavior if the component rendered by the '/' route should display regardless of the current route.
But what if you only want the Home component to be visible to users on the home page and not to those who have navigated to /sign-up? By using React Router’s exact prop on the first route, you can ensure that the route will match only if the current URL is an exact match.
<Route exact path='/'>
<Home />
</Route>
Now, when a user visits /, the Home component will render. But when a user visits /sign-up, only the second route will match and only the SignUp component will render.
React Router provides a couple of additional props—strict and sensitive—on the Route component for fine-tuning when a particular route should match, however, these are used far less frequently than the exact prop.
Here is the continuation:
Top comments (0)