React Router URL Segments: Dynamic Routes, Search Params & Fragments
React Router - URL Segments
In this post, we'll dive into routing concepts like dynamic segments, optional segments and fragments (URL hashes), which are crucial when working with React Router.
Dynamic Segments
Dynamic segments are used to pass parameters in the URL, which are then accessible in your React components.
For instance, consider a scenario where you have a blog app, and each post has a unique ID. To access the details of a specific post, you can use dynamic segments in the route path:
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import Post from "./Post";
function App() {
return (
<Router>
<Routes>
<Route path="/post/:id" element={<Post />} />
</Routes>
</Router>
);
}
In the example above, :id
is a dynamic segment. When a user navigates to /post/123
, React Router will match the route and pass the id
parameter to the Post
component.
useParams
To access the dynamic parameter inside the Post
component, we use the useParams
hook:
import { useParams } from "react-router-dom";
function Post() {
const { id } = useParams(); // Get the dynamic segment (id)
return <div>Post ID: {id}</div>;
}
Splats
In React Router, splats (*
) capture all remaining URL segments after a certain point. It's often used for wildcard routes or catch-all routes. For example, you could create a route that matches any URL that starts with /files
:
<Route path="/files/*" element={<Files />} />
Here, *
will capture everything after /files
, so if the user visits /files/documents/notes
, the Files
component will render with the appropriate logic to handle the URL.
To get the splat value inside a component, you can use the useParams
hook:
import { useParams } from "react-router-dom";
function Files() {
const { "*": remainingPath } = useParams(); // Get the splat (remaining path)
return <div>Remaining Path: {remainingPath}</div>;
}
If the user visits /files/documents/notes
, remainingPath
will be documents/notes
.
Search Parameters
Search parameters (query strings) are the part of the URL that comes after the ?, often used to pass dynamic data like filters, page numbers, or user preferences.
/products?category=shoes&page=2
useSearchParams
You can access the query parameters using the useSearchParams
hook, which gives you a way to read and manipulate the query string.
-
How to Access Search Parameters
import { useSearchParams } from "react-router-dom";
function ProductList() {
const [searchParams] = useSearchParams();
const category = searchParams.get("category");
const page = searchParams.get("page");
return (
<div>
<h2>Category: {category}</h2>
<p>Page: {page}</p>
</div>
);
} -
Setting or Updating Search Parameters
import { useSearchParams } from "react-router-dom";
function FilterButtons() {
const [searchParams, setSearchParams] = useSearchParams();
const handleClick = () => {
setSearchParams({ category: "shoes", page: "1" });
};
return <button onClick={handleClick}>Filter Shoes</button>;
} -
Preserve Existing Params While Updating
setSearchParams((prev) => {
prev.set("sort", "price");
return prev;
});
Fragments (URL Hashes)
Fragments (or URL hashes) are the part of a URL that comes after #
.
They are useful for navigating to specific sections of a page, such as when you want to link directly to a specific section of an article.
useLocation
You can use the useLocation
hook from React Router to read the fragment (hash) part of the URL:
import { useLocation } from "react-router-dom";
import { useEffect } from "react";
function About() {
const location = useLocation();
useEffect(() => {
if (location.hash) {
const element = document.getElementById(location.hash.substring(1));
if (element) {
element.scrollIntoView({ behavior: "smooth" });
}
}
}, [location.hash]);
return (
<div>
<h2>About Page</h2>
<div id="contact">Contact Section</div>
</div>
);
}