Published on January 20, 2025
React is one of the most popular libraries in modern web development for creating user interfaces (UIs). It provides a set of tools to help developers create interactive and reusable components using a component-based architecture. React focuses on building the UI only, so routing (navigating between different views or pages) is not built into the library and is supplied by additional libraries like React Router.
Routing is essential for creating anything more than basic applications, as it allows users to move between different pages of the app while loading the relevant content for each route.
In this post, you'll learn the fundamentals of React routing, from setting up routes to implementing advanced features like dynamic routes and lazy loading. By the end, you will have the knowledge to implement React routing in your own applications.
Routing is a mechanism that allows users to navigate between different pages or sections of a web application, usually triggered in response to a link or button being clicked in the UI.
There are two different kinds of routing in React, depending on how your application is built and deployed: server side and client side. These approaches exist because of the evolving need to balance performance, interactivity, and user experience.
In server-side routing, each navigation request triggers a full page reload, fetching and rendering a new HTML document from the server. This approach is effective, but can result in slower user experiences due to network latency, full page reload (rather than just the parts that need to be reloaded), and rendering time on the server.
Client-side routing is managed directly in the browser using JavaScript. Instead of reloading the entire page, the browser fetches and renders only the content that needs to be updated. So, the client-side router will simulate a full page reload by deciding which JavaScript components or views to show based on the route provided to it on the front end. This is the foundation of single-page applications (SPAs), which aim to improve user experience by avoiding full page reloads.
As React is a library that is often used to create SPAs, routing in React is typically handled on the client side using libraries such as react-router-dom, which is the most popular React routing library. It offers features such as dynamic routing, nested routes, and query parameter handling. Other alternatives include Reach Router, which is just a lightweight version of React Router, and Next.js, which is designed for server-side rendering (SSR) and hybrid routing.
This tutorial will use react-router-dom, which provides the following key features that are essential to implementing routing in React:
Dynamic routes: Routes that are defined using UI components, allowing for flexibility and easy updates.
Nested routes: The ability to organize and manage complex routing hierarchies for descriptive URLs and maintainability.
Route parameters: Support for dynamic parameters in URLs, for example, supplying the ID of a blog post that should be loaded (/blog/:id
).
Redirects and guards: Ways to control user access with redirects or route protection based on conditions.
Hooks: Built-in function hooks such as useNavigate
and useParams
, to simplify route handling.
Lazy loading: A way to optimize performance by loading components only when needed.
The React Router library provides different types of routing to manage navigation. Each router is suited to specific use cases depending on the kind of application you're building.
Below is an explanation of the different React routing types and when to use them, with a code example for each:
When routing in React, the BrowserRouter is the most commonly used router for building web applications. It uses the HTML5 history
API to keep the UI in sync with the URL, resulting in clean and user-friendly URLs. Use BrowserRouter
if you have a web application hosted on a server capable of handling dynamic routes — which just means your server will be set up to always serve the same index.html
file for any route and let React handle the routing entirely on the client side.
The HashRouter in React routing uses the hash portion of the URL (e.g. http://example.com/#/about
) to manage routing: anything after the hash is not sent to the server, then it uses JavaScript to map the portion after the hash to a component. The hash router is ideal for environments where the server cannot handle dynamic routes, when hosting a static site, or when backward compatibility with older browsers is required.
The React Router library's MemoryRouter stores the navigation history in memory rather than syncing it with the browser's URL bar. This routing method doesn't affect or rely on the browser's address bar, making it suitable for building navigation for client-side applications and native apps using tools like React Native to implement React Native routing.
If you would prefer to start your own project, to start routing in React, you will first need to install the react-router-dom
package:
npm install react-router-dom
Import the necessary components for setup in your App.js
or equivalent entry file:
The <Router>
component wraps your application and provides the routing context. Both <Routes>
and <Route>
define the paths and the components to render for each route. You will need to manually edit the URL to switch between routes in this example.
You can find example code here.
You can use the onClick
event trigger in React and the useNavigate
hook from React Router to move between the routes/pages of your application:
The above example has two separate components: Home, which is displayed at the default route of the application, and About. Both have a navigation button, which uses the useNavigate hook to allow routing between the two.
You can find example code here.
When a user tries to access a route that doesn't exist, you should tell them (usually in the form of a ”page not found” message with a link back to the home page). In React routing, you can achieve this with a fallback route:
Now, when you try to access a route that doesn't exist, you will see a message "404: Page not found" with a navigation button taking you back to the homepage.
You can find example code here
Here is a summary of the key hooks you can use in React Router
:
Hook | Purpose | Typical use case |
---|---|---|
Navigate programmatically | Redirect after form submission, etc. | |
Get the current route information | Check the pathname or route state | |
Access dynamic route parameters | Retrieve values like /user/:id | |
Define routes dynamically in components | Configure routes programmatically | |
Work with query parameters in the URL | Filter or sort data via queries |
You can use a combination of hooks and components when routing in React to achieve custom functionality. For example, you may want a certain part of your app to be inaccessible until a user logs in. Please note the following is just an example of authentication, and in a real-world scenario, you would need to implement security measures such as token-based authentication:
Above, the authentication status is stored in a boolean variable named isAuthenticated
in the application state, which is set to true
or false
by clicking the login button (this is for example purposes; in a full application you'd actually authenticate the user). The state is passed to the PrivateRoute
component, which is wrapping the Dashboard
. Depending on the value of the isAuthenticated
variable, it either displays the component or navigates the user to the Login
component.
From the PrivateRoute
, the Location
is passed to the Login
component with the useLocation
hook, so it knows where the user was trying to get to, and, once they’re logged in, can redirect them to their intended destination. The Link
component is also being used, which is an alternative to using a button with an onClick
event listener, and the useNavigate
hook is a way you can programmatically navigate a user without requiring an interaction from them.
You can find example code here.
Dynamic routing in React allows you to create routes with placeholders that can match dynamic segments in the URL. The useParams
hook lets you access this functionality.
In the App component example above, the Link component is used to pass through dynamic blogId variables to the route, and when it routes to the BlogArticle component, the useParams hook is used to extract that blogId and display it in the UI. It could be used for a network call to fetch specific blog information, for example.
You can find example code here.
Lazy loading in React allows you to load components only when they are needed, improving performance by reducing the initial load time of your application.
The below code shows how to use React.lazy and React.Suspense together with React Router
to load the components dynamically only when their respective routes are accessed:
Example code.
Search engine crawlers rely on fully rendered HTML to index pages effectively. Since React handles routing on the client side, it initially serves a minimal HTML file, and the rest of the content is rendered dynamically in the browser. This can result in incomplete or poorly indexed pages if crawlers are unable to execute JavaScript efficiently or if there are delays in rendering. These limitations make SPAs (with client-side routing) difficult to optimize for search engines.
If you are planning on applying SEO to your apps, you should consider using a framework like Next.js, which solves the SEO challenges discussed in the last section by using server-side rendering (SSR) to pre-render pages on the server before they are sent to the browser. This ensures that search engine crawlers receive fully rendered HTML, improving indexing and visibility.
Frameworks like Next.js have simplified routing by providing developers with the ability to create routes based on the file structure without extra configuration, so you can easily build nested routes, fine-tune route behavior with middleware, and add params to your filenames for easy dynamic routing.
Using react-router-dom
to handle your routing in React with a composable content platform like Contentful can be an effective choice for content-heavy websites, allowing you to compose your back end quickly and manage routing and dynamic content, simply delivering highly personalized experiences to your users worldwide.
Combining routing in React with react-router-dom
, and lazy loading features with Contentful's REST and GraphQL APIs, is a powerful way to build fast, responsive, and content-driven applications. By lazy loading routes and components, your app can cut down its initial load time, while Contentful ensures that content is delivered quickly from multiple edge locations via its globally distributed CDN.
You can bootstrap your own React app, already configured for Contentful with our React starter, or use our Next.js starter app, which is optimized for Contentful, including server-side rendering and dynamic content fetching.
Subscribe for updates
Build better digital experiences with Contentful updates direct to your inbox.