Dynamic Navigation with React Router

Image by Jared Murray.

Navigation is at the very core of any web application. Users expect smooth transitions between pages, and React Router makes this easy to achieve without fullpage reloads. Whether we are building a simple website or a complex singlepage application, React Router provides the tools we need to handle navigation dynamically.

In this article, I will explore how React Router works, how to set up dynamic routes, and best practices for managing navigation effectively.


Setting Up React Router

To get started with React Router, we need to install the package:

yarn add react-router-dom

Once installed, we can wrap our application with BrowserRouter to enable routing:

import { BrowserRouter, Routes, Route } from "react-router-dom";import HomePage from "./HomePage";import AboutPage from "./AboutPage";const App = () => (  <BrowserRouter>    <Routes>      <Route path="/" element={<HomePage />} />      <Route path="/about" element={<AboutPage />} />    </Routes>  </BrowserRouter>);export default App;

This setup defines two routes: the home page (/) and the about page (/about). React Router renders the appropriate component based on the URL.

Now that our routes are in place, we need a way for users to navigate between them efficiently. This is where React Router's <Link> component comes in.


Instead of using traditional anchor (<a>) tags, React Router provides the <Link> component to enable clientside navigation, which can be used like this:

import { Link } from "react-router-dom";const Navigation = () => (  <nav>    <Link to="/">Home</Link>    <Link to="/about">About</Link>  </nav>);export default Navigation;

By using the <Link> component, we can ensure that navigation is handled efficiently, preventing fullpage reloads and improving the user experience.


Using Dynamic Route Parameters

Many applications need flexible URLs. For example, a user profile page might need to display details based on the username in the URL. React Router makes this easy with dynamic route parameters.

We can access route parameters using useParams, like this:

import { useParams } from "react-router-dom";const Profile = () => {  const { username } = useParams();  return <h1>Profile of {username}</h1>;};

.. and to define a route that accepts a parameter:

<Routes>  <Route path="/profile/:username" element={<Profile />} /></Routes>

Now, navigating to /profile/ellie will display Profile of ellie, with username dynamically retrieved from the URL. Treat route parameters as untrusted input when they are sent to a server or used to look up protected data.


Handling Programmatic Navigation

Sometimes, we need to navigate users dynamically, such as after form submission or authentication. React Router provides the useNavigate hook for this, which we can use like this:

import { useNavigate } from "react-router-dom";const Login = () => {  const navigate = useNavigate();  const handleLogin = () => {    // Wait for the server to confirm authentication    navigate("/dashboard");  };  return <button onClick={handleLogin}>Log In</button>;};

Calling navigate("/dashboard") will update the URL programmatically, directing users to the dashboard after the server has confirmed their login. Changing the URL does not authenticate the user.


Redirecting Client‑Side Routes

Some parts of an application's interface should only be shown under certain conditions. For example, a dashboard might require users to be logged in. A clientside route wrapper can handle the redirect, but it is presentation logic rather than a security boundary:

import { Navigate } from "react-router-dom";const ProtectedRoute = ({ isAuthenticated, children }: { isAuthenticated: boolean; children: JSX.Element }) => {  return isAuthenticated ? children : <Navigate to="/login" />;};// This controls the interface only. Authorise protected requests on the server.// Usage in routes<Routes>  <Route path="/dashboard" element={<ProtectedRoute isAuthenticated={userLoggedIn}><Dashboard /></ProtectedRoute>} /></Routes>;

Here, a user without the clientside authenticated state is redirected to the login page instead of seeing the dashboard interface. Every request for protected data and every sensitive mutation must still be authenticated and authorised on the server.


Best Practices for React Router Navigation

To keep navigation smooth and maintainable, consider the following best practices:

  1. Use Semantic URLs

    – Keep URLs meaningful and predictable (/profile/:id instead of /user?id=123).
  2. Handle Fallback Routes

    – Use a wildcard route (*), so users see a custom error page instead of a blank screen.
  3. Optimise Route Loading

    – Use lazy loading (React.lazy) to improve performance by loading components only when needed.
  4. Preserve Scroll Position

    – Implement logic to restore scroll position when navigating between pages.

By following these best practices, we can ensure that our navigation is structured, efficient, and userfriendly. Crawlable content also needs a suitable rendering strategy, such as server rendering or static generation; clientside navigation alone does not guarantee that search engines can discover or render every route.


Wrapping Up

React Router provides a powerful way to handle dynamic navigation in React applications. Route parameters, programmatic navigation, and conditional redirects can create a seamless interface without unnecessary page reloads, provided that trusted authorisation remains on the server.

Key Takeaways

  • React Router enables singlepage navigation, preventing fullpage reloads.
  • The <Link> component provides efficient clientside navigation.
  • Dynamic routes with parameters allow flexible URL structures.
  • useNavigate enables programmatic navigation for handling redirects.
  • Clientside route guards can redirect users, but protected data and mutations still require serverside authorisation.

Understanding these core concepts allows us to build responsive and intuitive navigation experiences in React applications.


Untangling a delivery problem?

Send the symptoms, constraints, and affected routes. I'll help identify whether the issue sits in the application, platform, content model, deployment path, or search surface.