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.
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
, defineRoute
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
).
- Line 26: Uses
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
- Open your terminal or command prompt and navigate to your React project directory.
- 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 theHome
component when the path is matched. - Line 18: Defines a route that matches the
/about
path and renders theAbout
component when this path is matched.
- Line 15: Uses the
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.
Link
and NavLink
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 fromreact-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 theclassName
prop. The correct way in React Router v6 to handle active styling is to use theclassName
prop with a function that checks theisActive
property, notactiveClassName
used in earlier versions.
- Line 14: A
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
fromreact-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 retrieveproductId
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 anh2
element that displays a message including theproductId
. This shows how to insert a value into JSX dynamically. - Line 13: A placeholder comment suggests where the fetched product details would be displayed.
- Line 5: Uses
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
anduseParams
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 extractuserId
from the route parameter. This shows how to access dynamic route parameters in React Router.
- Line 22: Uses
- 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 toHome
,/about
toAbout
, and /users to a nested route withUserList
as the index andUserDetails
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 asuserId
to theUserDetails
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
- Define a route that matches any path using a wildcard character (*).
- 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 theRoutes
component, establishing the context for routing. - Line 20-22: Inside
Routes
, defineRoute
components for different paths.- Line 20: A route for the root path (
"/"
) that renders theHome
component. - Line 21: A route for
"/about"
that renders theAbout
component. - Line 22: A catch-all route that matches any path not caught by the above routes and renders the NotFound component.
- Line 20: A route for the root path (
- Line 18-24: Use
- 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 theuseNavigate
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 tohandleSubmit
. - Line 22: A submit button for the login form.
- Line 20: The form element with an
- Line 5: Initializes
- 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
useLoaderData
,Route
, andRoutes
fromreact-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 5: Fetches data using
- Line 16-18: Defines a
LoadingPlaceholder
component that displays a loading message. This is shown while thePostList
component is loading its data. - Line 20-35: Defines the main
App
component.- Line 23-32: Sets up the router using
Routes
andRoute
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 24-31: A single route for “/posts” that renders the PostList component. The Suspense component wraps PostList to handle asynchronous data fetching with
- Line 23-32: Sets up the router using
- 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
, includingNavigate
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 ifisAuthenticated
is true, or redirecting to/login
.
- Line 17: Uses a ternary operator to decide between rendering the
- 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
andRoute
to define the application’s routing structure.- Line 28: Defines a route for the login page.
- Line 29-31: Wraps the
Dashboard
component in aProtectedRoute
, passing theisAuthenticated
state to render the Dashboard or redirect to /login conditionally.
- Line 21: Initializes an
- 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
, andRoutes
fromreact-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 9: Uses
- 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 usesSuspense
to wrap the lazy-loadedAbout
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
anduseLocation
hooks fromreact-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 callshandleSortChange
, passing the selected value.- Line 15-17: Inside the
<select>
, defines options for sorting. Thevalue
of each option will be used to modify the sort parameter in the query string.
- Line 15-17: Inside the
- Line 5: Uses
- 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.