React Router

React Router empowers you to craft intuitive navigation experiences for your React applications. Effortlessly define routes, manage dynamic content, and handle complex UI flows with a powerful and versatile library. React Router simplifies navigation structure, promotes code reusability, and streamlines the development process for interactive React applications.

React-Router
Table of Contents

React Router

React Router is a powerful library specifically designed to handle routing within React applications. It’s important to note that React Router is not part of the core React library and needs to be installed as an additional package. React Router allows you to build Single Page Applications (SPAs) with React, where the content changes dynamically without requiring a full page reload. This creates a seamless and app-like user experience.

React Router offers many features that streamline the development of Single Page Applications (SPAs) in React. Here’s a look at some key benefits:

  • Declarative Routing
    Define routes using JSX syntax, making your application’s navigation structure easy to understand and maintain.
  • Nested Routes
    Create hierarchical routing structures for complex SPAs with nested components, mirroring the organization of your application’s content.
  • Code Splitting
    Improve application performance by loading components only when their corresponding routes are accessed, resulting in faster initial page loads.
  • Ease of Use
    React Router provides a well-documented and intuitive API, making integrating routing functionalities into your React projects straightforwardly.

How React Router Works

  • Matches URLs to Components
    At its core, React Router matches the current URL in your web browser to specific React components that you define.
  • Updates the UI
    When the URL changes, React Router determines which components should be rendered. It updates the displayed UI accordingly, without a full page reload.
  • Manages Navigation
    It provides components and tools (like <Link>) to help you control navigation and create links within your React application that trigger routing updates.

Why Use React Router

  • Smooth User Experience
    Creates a more fluid and responsive user experience compared to traditional websites where every page navigation triggers a full page reload.
  • Organized Applications
    Helps organize large React applications by breaking them into smaller, manageable views that correspond to different URLs.
  • Browser History Support
    Integrates with browser history, allowing users to use the back and forward buttons as expected.

React Routes Example

import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';

function Home() {
    return <h1>Welcome to the Home Page!</h1>;
}

function About() {
    return <h1>Learn more about us on the About Page!</h1>;
}

function Products() {
    return <h1>Browse our Products!</h1>;
}

function ProductDetails() {
    return (
        <div>
            <h2>Product Details</h2>
        </div>
    );
}

function App() {
    return (
        <Router>
            <Routes>
                <Route path="/" element={<Home />} />
                <Route path="/about" element={<About />} />
                <Route path="/products" element={<Products />} />
                <Route path="/products/:productId" element={<ProductDetails />} />
            </Routes>
        </Router>
    );
}

export default App;

Explanation

  • Line 1 & 2: Import the React library and react-router-dom components necessary for the app’s routing.
  • Line 4-6, 8-10, 12-14: Define functional components (Home, About, Products) that return JSX for different pages.
  • Line 16-21: Define a ProductDetails component to show specific product details. However, it’s missing logic to display productId from the route parameter.
  • Line 24-35: Define the main App component which includes the router setup.
    • Line 26: Uses Router to enable routing within the app.
    • Line 27-32: Inside Routes, define Route components to map URL paths to the respective components. This setup includes a route for home (/), about (/about), products listing (/products), and product details (/products/:productId).

This example showcases nested routes. Users can navigate to individual product details pages using URLs like /products/123 or /products/456. React Router effectively manages the routing logic and renders the corresponding components based on the matched path and parameters.


React Router Installation and Setup

React Router, specifically the react-router-dom package, empowers you to manage navigation within your React applications. Here’s a quick guide to get you started:

Installation

  1. Open your terminal or command prompt and navigate to your React project directory.
  2. Use npm or yarn to install react-router-dom
npm install react-router-dom

OR

yarn add react-router-dom

Basic Setup

Import the components from react-router-dom in your main application component (often called App.js).

Basic Setup Example

import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';

// Your application components
function Home() {
    return <h1>Welcome to the Home Page!</h1>;
}

function About() {
    return <h1>Learn more about us on the About Page!</h1>;
}

function App() {
    return (
        <Router>
            <Routes>
                <Route path="/" element={<Home />} />
                <Route path="/about" element={<About />} />
            </Routes>
        </Router>
    );
}

export default App;

Explanation

  • Lines 1 & 2: Imports the React library and several components from react-router-dom. This setup is essential for using React Router in the application.
  • Line 5-7: Defines a Home component that renders the homepage content.
  • Line 9-11: Defines an About component that renders content for the about page.
  • Line 13-21: Defines the main App component, which includes the router setup.
    • Line 15: Uses the Router component to enable routing within the app. It wraps all route definitions.
    • Line 16: The Routes component defines a group of route rules within the application.
    • Line 17: Defines a route that matches the root path (/) and renders the Home component when the path is matched.
    • Line 18: Defines a route that matches the /about path and renders the About component when this path is matched.

Remember:This is a basic example. React Router offers many features for more complex navigation scenarios. Refer to the official documentation for further details.


Core Components

At the foundation of React Router lie core components that enable you to shape your application’s navigation experience. Key players include BrowserRouter (or its alternatives) to establish the routing context for browser-based SPAs, the Routes component to group route definitions, and the Route component to define specific mappings between URL paths and React components. Link and NavLink (with its active state styling capability) become essential tools within your React project to facilitate the creation of navigation links.

BrowserRouter

React Router provides various routing components to cater to diverse development environments. The most commonly used component for browser-based SPAs is BrowserRouter.

BrowserRouter

BrowserRouter integrates seamlessly with the browser’s history API, enabling navigation through the address bar, forward and back buttons, and bookmarks. It’s the go-to choice for traditional client-side React applications running in a web browser.

Routes and Route

React Router utilizes two key components to define navigation logic within your application: Routes and Route.

  • Routes: This parent component is a container that groups your application’s individual route definitions. It establishes the overall routing context and ensures that only one child Route component can match a URL path at a time.
  • Route: The Route component defines a specific mapping between a URL path and the React component that should be rendered for that path. It’s the building block for creating navigation rules within your React SPA.

React Router provides two components for creating navigation links within your application: Link and NavLink. Both components handle navigation but cater to slightly different use cases.

  • Link: This is the fundamental component for creating navigation links in React Router. It renders an anchor (<a>) tag and handles the navigation logic when clicked.
  • NavLink: A specialized version of Link, NavLink offers additional features specifically designed for navigation menus. It handles navigation and provides visual cues to indicate which link is active based on the URL.

Link vs. NavLink Example

import React from 'react';
import { Link, NavLink } from 'react-router-dom';

function Home() {
    return <h1>Welcome to the Home Page!</h1>;
}

function About() {
    return <h1>Learn more about us on the About Page!</h1>;
}

function App() {
    return (
        <nav>
            <ul>
                <li>
                    <Link to="/">Home</Link>
                </li>
                <li>
                    <NavLink to="/about" className={({ isActive }) => isActive ? "active" : ""}>About</NavLink>
                </li>
            </ul>
        </nav>
    );
}

export default App;

Explanation

  • Line 1 & 2: Import the React library and Link, NavLink components from react-router-dom. These are essential for navigation within the app.
  • Line 4-6 & 8-10: Define Home and About components that return JSX for different pages. They are placeholders to demonstrate component setup.
  • Line 12-24: Defines the App component, which includes navigation links.
    • Line 14: A <nav> element is used to wrap navigation links, serving as the app’s navigation bar.
    • Line 15-22: An unordered list <ul> is used to list navigation items.
    • Line 17: The Link component creates a link to the home page. It is used for navigation without active state styling.
    • Line 20: The NavLink component creates a link to the about page and applies active styling using the className prop. The correct way in React Router v6 to handle active styling is to use the className prop with a function that checks the isActive property, not activeClassName used in earlier versions.

Choosing the Right One

Use Link for general navigation links where visual indication of the active link isn’t necessary. For navigation menus where you want to highlight the current page, NavLink is a better option due to its built-in active state styling capabilities.

Grabbing Parameters with useParams

React Router’s useParams hook empowers you to access dynamic parameters from the URL within your React components. This is particularly useful when building features like product detail pages or user profile pages that require unique data based on a specific parameter value.

How it Works

The useParams hook retrieves an object containing key-value pairs where the keys represent the parameter names defined in your route paths, and the values are the corresponding parameter values extracted from the URL.

Using useParams Example

import React from 'react';
import { useParams } from 'react-router-dom';

function ProductDetails() {
    const { productId } = useParams(); // Destructure productId param

    // Fetch product details based on productId
    // ... (logic to fetch data using productId)

    return (
        <div>
            <h2>Product Details for ID: {productId}</h2>
            {/* Display product details fetched based on productId */}
        </div>
    );
}

export default ProductDetails;

Explanation

  • Line 1 & 2: Import React and useParams from react-router-dom. useParams is a hook used to access parameters from the URL.
  • Line 4-15: Defines the ProductDetails component that displays product details based on a product ID obtained from the URL.
    • Line 5: Uses useParams to destructure and retrieve productId from the URL parameters. This ID is used to fetch and display the product’s details.
    • Line 7: A placeholder comment indicates where the logic to fetch product details based on productId should be implemented.
    • Line 10-14: Renders a div containing an h2 element that displays a message including the productId. This shows how to insert a value into JSX dynamically.
    • Line 13: A placeholder comment suggests where the fetched product details would be displayed.

Remember

  • Ensure your route path definition includes the dynamic parameter using a colon (:) followed by the parameter name (e.g., /products/:productId).
  • The useParams hook is typically used within components rendered by routes that contain dynamic parameters.

Nesting Routes with Outlet

React Router’s Outlet component acts as a placeholder within parent route components, enabling you to create nested routing structures within your React application. This is beneficial for organizing complex UIs with hierarchical navigation.

How it Works

The Outlet component is a designated spot where child routes defined within the parent route can render their content. This allows you to define a layout for the parent route and leverage child routes for specific sections within that layout.

Using Outlet for Nested Routes Example

import React from 'react';
import { Routes, Route, Outlet, Link, useParams } from 'react-router-dom';

function Home() {
    return <h1>Welcome to the Home Page!</h1>;
}

function About() {
    return <h1>Learn more about us on the About Page!</h1>;
}

function UserList() {
    return (
        <div>
            <h2>List of Users</h2>
            {/* Display a list of users */}
        </div>
    );
}

function UserDetails() {
    const { userId } = useParams();
    return (
        <div>
            <h2>User Details for ID: {userId}</h2>
            {/* Display user details based on userId */}
        </div>
    );
}

function App() {
    return (
        <div>
            <nav>
                <ul>
                    <li><Link to="/">Home</Link></li>
                    <li><Link to="/about">About</Link></li>
                    <li><Link to="/users">Users</Link></li>
                </ul>
            </nav>
            <main>
                <Routes>
                    <Route path="/" element={<Home />} />
                    <Route path="/about" element={<About />} />
                    <Route path="/users" element={<Outlet />}>
                        <Route index element={<UserList />} />  {/* 'index' for default route within /users */}
                        <Route path=":userId" element={<UserDetails />} />  {/* Dynamic route for user details */}
                    </Route>
                </Routes>
            </main>
        </div>
    );
}

export default App;

Explanation

  • Line 2: Imports necessary components from react-router-dom. Outlet and useParams are specifically used for nested routing and accessing dynamic route parameters.
    • Outlet is used to render child routes.
    • useParams is a hook for accessing parameters of the current route.
  • Line 4-6: Defines the Home component, which returns the home page content.
  • Line 8-10: Defines the About component, which returns the about page content.
  • Line 12-19: Defines the UserList component, which is supposed to return a list of users.
  • Line 21-28: Defines the UserDetails component to display details for a specific user, identified by userId.
    • Line 22: Uses useParams to extract userId from the route parameter. This shows how to access dynamic route parameters in React Router.
  • Line 31-53: Defines the main App component, setting up the navigation and routing for the application.
    • Line 36-38: Links for navigating to different pages.
    • Line 42-49: Sets up routes for different components. / routes to Home, /about to About, and /users to a nested route with UserList as the index and UserDetails for dynamic user IDs.
      • Line 45: Outlet acts as a placeholder for nested routes, which allows child user routes to render within the parent layout.
      • Line 46: An index route within /users to display a default view (list of users) when the user navigates to /users directly.
      • Line 47: A dynamic route for user details, where :userId is a variable path segment that matches any value and passes it as userId to the UserDetails component.

This example showcases nested routes. Users can navigate between Home, About, Users list, and individual User detail pages using the navigation links. The Outlet component ensures child routes (UserList and UserDetails) are rendered within the designated area of the parent route (/users).


Handling 404 Errors with React Router

While you strive to provide a seamless navigation experience, users can always land on unmatched URLs. React Router allows you to gracefully handle these cases using a “Not Found” route.

Approach

  1. Define a route that matches any path using a wildcard character (*).
  2. Render a component specifically designed to display a “Not Found” message or redirect users to a default page.

Setting Up a Not Found Route Example

import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';

function Home() { ... }
function About() { ... }

function NotFound() {
    return (
        <div>
            <h2>404 - Not Found!</h2>
            <p>Sorry, the page you requested was not found.</p>
        </div>
    );
}

function App() {
    return (
        <Router>
            <Routes>
                <Route path="/" element={<Home />} />  {/* Matches root path */}
                <Route path="/about" element={<About />} />  {/* Matches /about path */}
                <Route path="*" element={<NotFound />} />  {/* Catches all unmatched paths */}
            </Routes>
        </Router>
    );
}

export default App;

Explanation

  • Line 1-2: Import React library and necessary components from react-router-dom. BrowserRouter is renamed to Router for simplicity.
  • Lines 4 & 5: Define the Home and About components. These components are placeholders, assuming they return relevant JSX for their pages.
  • Line 7-14: Defines the NotFound component, which returns a message indicating the page was not found. Useful for handling 404 errors.
  • Line 16-26: Defines the main App component which sets up the router and defines the application’s routes.
    • Line 18-24: Use Router to wrap the Routes component, establishing the context for routing.
    • Line 20-22: Inside Routes, define Route components for different paths.
      • Line 20: A route for the root path ("/") that renders the Home component.
      • Line 21: A route for "/about" that renders the About component.
      • Line 22: A catch-all route that matches any path not caught by the above routes and renders the NotFound component.
  • Line 28: Exports the App component, making it available for use in other application parts.

With this setup, if a user attempts to access a non-existent URL (e.g., /invalid-page), the NotFound component will be rendered, displaying a user-friendly message indicating the page cannot be found.


Programmatic Navigation with useNavigate

React Router provides the useNavigate hook from react-router-dom for programmatically triggering navigation within your React components. This is useful when redirecting users based on certain events or actions within your application, such as after a successful form submission or login.

How it Works

The useNavigate hook grants you access to a function that you can call to programmatically navigate the user to a different URL within your React application.

Programmatic Navigation with useNavigate Example

import React from 'react';
import { useNavigate } from 'react-router-dom';

function LoginForm() {
    const navigate = useNavigate();

    const handleSubmit = (event) => {
        event.preventDefault();
        // Simulate successful form submission (replace with your logic)
        const loginSuccess = true;

        if (loginSuccess) {
            navigate('/dashboard');  // Programmatic navigation to dashboard
        } else {
            // Handle login failure (e.g., display error message)
        }
    };

    return (
        <form onSubmit={handleSubmit}>
            {/* Login form fields */}
            <button type="submit">Login</button>
        </form>
    );
}

export default LoginForm;

Explanation

  • Line 1 & 2: Imports the necessary modules from React and react-router-dom. Specifically, useNavigate is a hook used for navigation.
  • Line 4-25: Defines the LoginForm functional component.
    • Line 5: Initializes navigate, a function provided by the useNavigate hook, allowing for programmatic navigation.
    • Line 7-17: Declares handleSubmit, a function that prevents the default form submission behavior, checks login success, and navigates to /dashboard on success.
      • Line 10: Simulates a successful login. Replace this logic with actual authentication logic.
      • Line 12-16: Uses an if statement to check if login is successful. If so, it navigates to the /dashboard route. If not, an error-handling mechanism should be implemented.
    • Line 19-24: Returns a form element that, when submitted, calls the handleSubmit function.
      • Line 20: The form element with an onSubmit event handler set to handleSubmit.
      • Line 22: A submit button for the login form.
  • Line 27: Exports the LoginForm component for use in other application parts.

The useNavigate hook empowers you to achieve dynamic navigation control within your React components, enhancing the flexibility and responsiveness of your user experience.


Advanced Concepts

While React Router’s core lies in navigation and route management, it also offers tools for sophisticated use cases. You can optimize performance with code splitting and lazy loading (made easy with React.lazy and Suspense) to improve initial load times. Protecting routes based on authentication checks ensures that only authorized users access sensitive areas of your application. Nesting routes allow you to build complex user interfaces with clear hierarchical navigation structures. For dynamic and data-driven experiences, useLoaderData seamlessly integrates data fetching directly into your route definitions.

Data Fetching and Loading Indicators with React Router

React Router offers functionalities to manage data fetching and loading states within your application. This ensures a smooth user experience by displaying informative placeholders or loaders while data is retrieved.

Data Fetching with useLoaderData

The useLoaderData hook from third-party libraries like react-router-dom/server lets you fetch data directly within your route definitions. This data can then be passed as props to your component, eliminating the need for separate data fetching logic.

Suspense and Loading States

The Suspense component from React allows you to declaratively specify loading states for components that rely on asynchronous data fetching. This ensures the UI doesn’t render incomplete data and provides visual feedback to users while data is being loaded.

useLoaderData and Suspense Example

import React, { Suspense } from 'react';
import { useLoaderData, Route, Routes } from 'react-router-dom/server';

function PostList() {
    const posts = useLoaderData();

    return (
        <ul>
            {posts.map((post) => (
                <li key={post.id}>{post.title}</li>
            ))}
        </ul>
    );
}

function LoadingPlaceholder() {
    return <div>Loading posts...</div>;
}

function App() {
    return (
        <div>
            <Routes>
                <Route
                    path="/posts"
                    element={
                        <Suspense fallback={<LoadingPlaceholder />}>
                            <PostList />
                        </Suspense>
                    }
                />
            </Routes>
        </div>
    );
}

export default App;

Explanation

  • Line 1: Imports React and Suspense for handling the rendering of async components.
  • Line 2: Imports useLoaderDataRoute, and Routes from react-router-dom/server, assuming server-side rendering is intended.
  • Line 4-14: Defines the PostList component.
    • Line 5: Fetches data using useLoaderData(), assumed to be provided by some server-side logic not shown here.
    • Line 7-13: Returns a list (<ul>) of posts. Each post is represented as a list item (<li>) with a unique key and displays the post’s title.
  • Line 16-18: Defines a LoadingPlaceholder component that displays a loading message. This is shown while the PostList component is loading its data.
  • Line 20-35: Defines the main App component.
    • Line 23-32: Sets up the router using Routes and Route to define the path and component to render for that path.
      • Line 24-31: A single route for “/posts” that renders the PostList component. The Suspense component wraps PostList to handle asynchronous data fetching with LoadingPlaceholder specified as the fallback content to display while loading.
  • Line 37: Exports the App component for use in other application parts.

This example allows for server-side data loading with useLoaderData and client-side dynamic content loading with Suspense, ensuring that the UI remains responsive and provides feedback to the user while waiting for data.

Protected Routes with React Router

React Router doesn’t inherently provide built-in mechanisms for authorization. However, you can leverage various techniques to secure specific routes within your application based on a user’s authentication state.

Common Approaches

  • Conditional Rendering
    Check the authentication state within your component and conditionally render the protected content if the user is authorized.
  • Higher-Order Components (HOCs)
    Create reusable HOCs that wrap your protected components, handling authentication checks and redirects if necessary.
  • Separate Authentication Library
    Integrate a dedicated authentication library to manage user sessions and provide hooks or components for authorization checks.

Conditional Rendering with ProtectedRoute Example

import React from 'react';
import { Route, Routes, Navigate } from 'react-router-dom';

function LoginPage() {
    // Login form logic
}

function Dashboard() {
    return (
        <div>
            <h2>Welcome to the Dashboard!</h2>
        </div>
    );
}

function ProtectedRoute({ children, isAuthenticated }) {
    return isAuthenticated ? children : <Navigate to="/login" />;
}

function App() {
    const [isAuthenticated, setIsAuthenticated] = React.useState(false);  // Simulate authentication state

    // Login logic to update isAuthenticated state (replace with your implementation)

    return (
        <div>
            <Routes>
                <Route path="/login" element={<LoginPage />} />
                <Route path="/dashboard" element={<ProtectedRoute isAuthenticated={isAuthenticated}>
                    <Dashboard />
                </ProtectedRoute>} />
            </Routes>
        </div>
    );
}

export default App;

Explanation

  • Line 1 & 2: Imports React and necessary components from react-router-dom, including Navigate for redirecting users.
  • Line 4-6 & 8-14: Define placeholder components LoginPage and Dashboard for demonstration purposes.
  • Line 16-18: Defines a ProtectedRoute component that checks if the user is authenticated. If not, it redirects to the /login page using the <Navigate> component.
    • Line 17: Uses a ternary operator to decide between rendering the children components if isAuthenticated is true, or redirecting to /login.
  • Line 20-34: Defines the main App component with an authentication state.
    • Line 21: Initializes an isAuthenticated state to simulate user authentication.
    • Line 27-32: Uses Routes and Route to define the application’s routing structure.
      • Line 28: Defines a route for the login page.
      • Line 29-31: Wraps the Dashboard component in a ProtectedRoute, passing the isAuthenticated state to render the Dashboard or redirect to /login conditionally.
  • Line 37: Exports the App component for use in other application parts.

This example demonstrates conditional rendering within a custom ProtectedRoute component. You can replace the simulated authentication state with your application’s logic to determine whether a user is authorized to access protected routes.

Code Splitting and Lazy Loading with React Router

React applications can grow large, impacting initial load times. Code splitting and lazy loading techniques offered by React Router help optimize performance by loading components only when needed.

The Strategy

  • Code Splitting: Break down your application codebase into smaller bundles.
  • Lazy Loading: Defer the loading of specific components until they are required by the user’s navigation, reducing the initial bundle size.

React.lazy and Suspense

  • React.lazy allows you to define a function that dynamically imports a component at runtime.
  • Suspense serves as a wrapper component, providing a fallback UI (like a loading indicator) while the lazy-loaded component is being fetched.

Lazy Loading with React.lazy and Suspense Example

import React, { Suspense } from 'react';
import { Link, Route, Routes } from 'react-router-dom';
const About = React.lazy(() => import('./About'));  // Lazy-loaded About component

function Home() {
    return (
        <div>
            <h2>Welcome to the Home Page!</h2>
            <Link to="/about">Learn More About Us</Link>
        </div>
    );
}

function App() {
    return (
        <div>
            <nav>
                <ul>
                    <li><Link to="/">Home</Link></li>
                    <li><Link to="/about">About</Link></li>
                </ul>
            </nav>
            <main>
                <Routes>
                    <Route path="/" element={<Home />} />
                    <Route
                        path="/about"
                        element={
                            <Suspense fallback={<div>Loading About...</div>}>
                                <About />
                            </Suspense>
                        }
                    />
                </Routes>
            </main>
        </div>
    );
}

export default App;

Explanation:

  • Line 1: Imports React and the Suspense component, which is used to render lazy-loaded components.
  • Line 2: Imports Link, Route, and Routes from react-router-dom for navigation and routing.
  • Line 3: Lazy loads the About component using React.lazy, which splits this component into a separate chunk loaded only when needed.
  • Line 5-12: Defines the Home component, which renders the homepage content and includes a link to the About page.
    • Line 9: Uses Link to create a navigable link to the About page without reloading the page.
  • Line 14-38: Defines the App component, the application’s main component that includes navigation and routes.
    • Line 17-22: Sets up a simple navigation menu with links to the Home and About pages.
    • Line 24-34: Uses Routes to define the application’s routing structure.
      • Line 25: Defines a route for the homepage.
      • Line 26-32: Defines a route for the About page. The element prop uses Suspense to wrap the lazy-loaded About component, with a fallback component displayed while the About component is loading.
  • Line 40: Exports the App component so it can be used elsewhere in the application.

By lazy-loading the About component, your application’s initial bundle size is reduced. The Suspense component ensures a smooth user experience by displaying a placeholder while the About component loads in the background.

Managing Navigation State in React Router

React Router provides functionalities for managing navigation history and state within your application. This lets you track the user’s navigation journey and potentially preserve state information across route transitions.

Common Strategies

  • useNavigate Hook
    This hook, from react-router-dom, grants you programmatic control over navigation, allowing you to push, replace, or go back in the navigation history.
  • useLocation Hook
    The useLocation hook, also from react-router-dom, provides access to the current location object, including information like the pathname, search parameters, and state (if provided).

Using useNavigate and useLocation Example

import React from 'react';
import { useNavigate, useLocation } from 'react-router-dom';

function ProductList() {
    const navigate = useNavigate();
    const location = useLocation();

    const handleSortChange = (sortBy) => {
        navigate(`/products?sort=${sortBy}`);
    };

    return (
        <div>
            <h2>Products</h2>
            <select onChange={(e) => handleSortChange(e.target.value)}>
                <option value="latest">Latest</option>
                <option value="price-asc">Price (Low to High)</option>
            </select>
            {/* Display product list based on sort parameter */}
        </div>
    );
}

export default ProductList;

Explanation

  • Line 1: Imports the React library necessary for defining components.
  • Line 2: Imports useNavigate and useLocation hooks from react-router-dom to programmatically navigate and access the current location’s information.
  • Line 4-21: Defines the ProductList component.
    • Line 5: Uses useNavigate to get a function that allows navigating programmatically.
    • Line 6: Uses useLocation to access the current URL’s location object, although it’s not directly used in this corrected example.
    • Line 8-10: Defines handleSortChange, a function that navigates to the /products path with a query string for sorting. It constructs the URL with the sort parameter.
    • Line 12-20: Renders the component, displaying a heading and a dropdown for sorting products. The onChange event of the <select> element calls handleSortChange, passing the selected value.
      • Line 15-17: Inside the <select>, defines options for sorting. The value of each option will be used to modify the sort parameter in the query string.
  • Line 24: Exports the ProductList component to other application parts.

This example demonstrates how to update the navigation state programmatically. When the user selects a sort option, the handleSortChange function utilizes navigate to update the URL (/products) and add a new state object ({ sort: sortBy }) containing the chosen sort criteria. Components along the route can then access this state to filter or display products based on the selected sort order.