Home > frontend > Easy Way To Implement URLSearchParams In React App Using ReactRouter (useSearchParams Hook).

Easy Way To Implement URLSearchParams In React App Using ReactRouter (useSearchParams Hook).

React router has been a key package for implementing navigation in React Apps. Its useSearchParams hook is a unique feature for storing data in the URL.

By :Thomas Inyang🕒 26 Jan 2025

searchparams

Introduction

In a website, the use of searchParams enables the storage and management of data directly in the URL, making it globally accessible across the app.


As a front-end developer working with ReactJS, you'll often use URL query parameters in projects like e-commerce sites, product listings, or any website with search and filter functionalities. With the data in the URL, users can share, bookmark, or revisit specific app states anytime.


To achieve the implementation of URLSearchParams in a React App, you can leverage the useSearchParams hook from React Router which is capable of handling query parameters simply and efficiently.


In this post, you'll learn about the following:

  1. How to setup useSearchParams hook (React Router) in your ReactJs application.
  2. Perform filtration of product by category using a mock product list.
  3. Perform a search of an item(s).
  4. Best Practices for Managing Query Parameters

Prerequisite

  1. Vite for React.
  2. ReactJs knowledge and JavaScript concepts.

Why do URL Query Parameters Matter in Modern Web Applications?

When you shop online and filter products by category, price range, or brand. Or perhaps you're browsing flight options, sorting results by price or duration. These dynamic interactions are powered by URL query parameters, which enable content to update instantly without page reloads.


URL query parameters offer several key advantages that make them essential in today's web applications:


  1. It enhances user experience by bookmarking specific search results or filtered views to revisit later.
  2. Links can be shared with others, displaying identical filtered content.
  3. Each parameter change can be tracked in the browser's history, enabling proper back/forward button functionality.
  4. The parameters maintain state across page refreshes, preserving user selections.
  5. Search engines can index specific parameter combinations, potentially improving discoverability.

See Also: How to Implement Dynamic Routing in ReactJs

When building Single Page Applications (SPAs) with React, the combination of React Router and the useSearchParams hook provides a seamless way to manage these parameters, while maintaining clean and well-structured code.

Getting Started with React Router and useSearchParams Hook

This section covers the initial steps for setting up the development environment with the necessary dependencies.


Step 1: Setting Up React Router

First, install React Router in your project:

npm i react-router-dom

If you're using React Router for the first time, update your main entry file (typically `main.jsx` or `main.tsx`) with the following configuration:

import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter, Routes, Route } from "react-router";

import App from "./app";
const root = document.getElementById("root");

ReactDOM.createRoot(root).render(
<StrictMode>
<BrowserRouter>
<Routes>
<Route path="/" element={<App />} />
</Routes>
</BrowserRouter>
</StrictMode>
);

With this setup, you've successfully enabled routing in your React application, establishing the foundation for implementing URL search parameters.


Step 2: Understanding the useSearchParams Hook

It is a powerful feature provided by React Router that simplifies working with URL query parameters instead of manual URL parsing and updating. It's a React-friendly way to interact with the browser's address bar and returns an array containing:

1. A `searchParams` object (similar to JavaScript's native `URLSearchParams`)

2. A `setSearchParams` function to update the parameters

How to Implement Product Filtration Using URL Search Parameters.

Now, let's build a practical example: filtering products by category using URL search parameters. This pattern is commonly used in e-commerce websites and product catalogs.


Step 1: Create Product Types

First, define a product type file (types.d.ts) in the root dir using TypeScript.

export interface Product {
sku: string;
name: string;
desc: string;
qty: number;
category: string;
price: number;
discount: number;
}

Step 2: Create Mock Product Data

For demonstration purposes, we'll create a mock product dataset. In a real application, this data would typically come from an API or database. Create a data folder and create a `productData.ts` file.

import { Product } from "./types";
export const products: Product[] = [
{
sku: "iph2838",
name: "iPhone 12",
desc: "clear camera",
qty: 10,
category: "phones",
price: 10000,
discount: 0,
},
{
sku: "sam4138",
name: "Samsung s21",
desc: "super fast",
qty: 10,
category: "phones",
price: 50303,
discount: 0,
},
{
sku: "hp394",
name: "HP pavilion G6",
desc: "Long lasting battery",
qty: 5,
category: "laptops",
price: 10000,
discount: 0,
},
{
sku: "hp004",
name: "HP EliteBook",
desc: "Long lasting battery",
qty: 5,
category: "laptops",
price: 130000,
discount: 0,
},
{
sku: "del994",
name: "Dell latitude",
desc: "Super fast system",
qty: 5,
category: "laptops",
price: 130000,
discount: 0,
},
];

Step 3: Implement Category Filter Component

Now create a component that uses the useSearchParams hook to filter products by category.

Create a `FilterParams.tsx` file in your components directory:

import React, { useEffect } from "react";
import { useSearchParams } from "react-router";
import { products } from "../productData";
import { Product } from "../types";

export default function FilterParams() {

const [filterParams, setFilterParams] = useSearchParams();

const category = filterParams.get("category") || "all";

const [filterResult, setFilterResult] = React.useState<Product[]>([]);

// Update filtered results whenever category changes
useEffect(() => {
if (category === "all") {
setFilterResult(products);
} else {
const temp = products.filter((el) => el.category === category);
setFilterResult(temp);
}
}, [category]);

// Update URL when filter changes
const handleFilterChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
setFilterParams({ category: event.target.value });
};

return (
<div className="filter-container">
<h2>Product Filter</h2>
<div className="filter-controls">

<label>
Filter by category:
<select onChange={handleFilterChange} value={category}>
<option value="all">All Products</option>
<option value="phones">Phones</option>
<option value="laptops">Laptops</option>
</select>
</label>

</div>

<h3>Showing results for: {category}</h3>

<div className="product-grid">
{filterResult.map((product: Product, index: number) => (
<div key={index} className="product-card">
<h4>{product.name}</h4>
<p>{product.desc}</p>
<p>Price: ${product.price}</p>
<p>Category: {product.category}</p>
</div>
))}
</div>
</div>
);
}

In this code:

1. The useSearchParams hook is used to access and manage URL query parameters.

2. The "category" parameter is extracted from the URL (defaulting to "all" if not present).

3. The filtered results whenever the category changes and when a different category is selected the URL triggers a re-render


This approach ensures that the selected category is always reflected in the URL, allowing users to bookmark or share specific filter states.

How To Implement And Use Search Functionality With Url Parameters.

Now implement a search feature to store and manage search queries.

Create a `SearchParams.tsx` file in your components directory:

components/SearchParams.tsx

```tsx

import React, { useEffect } from "react";
import { useSearchParams } from "react-router";
import { products } from "../productData";
import { Product } from "../types";

export default function SearchParams() {

const [searchParams, setSearchParams] = useSearchParams();
// Get the name from the URL or default to an empty string
const query = searchParams.get("name") || "";
const [searchResult, setSearchResult] = React.useState<Product[]>([]);
// Update search results when search button is clicked
const updateResults = () => {
if (query.trim() === "") {
setSearchResult([]);
return;
}
const filteredProducts = products.filter((product) =>product.name.toLowerCase().includes(query.toLowerCase())
);
setSearchResult(filteredProducts);
};
// Initialize search results on component mount and when query changes
useEffect(() => {
if (query) {
updateResults();
}
}, [query]);
// Update the URL
const handleSearchChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const newQuery = event.target.value;
setSearchParams(newQuery ? { name: newQuery } : {});
};

return (
<div className="search-container">
<h2>Product Search</h2>
<div className="search-controls">
<label>
Search products:
<input
type="text"
value={query}
onChange={handleSearchChange}
placeholder="Enter product name..."
/>
</label>
<button onClick={updateResults}>Search</button>
</div>

{query && <h3>Showing results for: "{query}"</h3>}

<div className="search-results">
{searchResult.length > 0 ? (
<div className="product-grid">
{searchResult.map((product: Product, index: number) => (
<div key={index} className="product-card">
<h4>{product.name}</h4>
<p>{product.desc}</p>
<p>Price: ${product.price}</p>
<p>Category: {product.category}</p>
</div>
))}
</div>
) : (
query && <p>No products found matching "{query}"</p>
)}
</div>
</div>
);
}

In this code:

1. useSearchParams manages the search query in the URL

2. The search term is extracted from the "name" parameter in the URL

3. When users type in the search box, the URL is updated in real-time

4. Case-insensitive is used to filter and match product names with the search query.

5. The results are displayed dynamically based on the current search term

See Also: Why Create React App (CRA) Was Deprecated.

This approach creates a seamless search experience while maintaining the search state in the URL for shareability and persistence.


Update Routes Configuration

Finally, update the routes configuration to include the new filter and search components:

<Routes>
<Route path="/" element={<App />} />
<Route path="/filter" element={<FilterParams />} />
<Route path="/search" element={<SearchParams />} />
</Routes>

With the above, users can navigate to `/filter` to access the category filter and `/search` to use the search functionality. Both features will maintain their state in the URL, allowing for bookmarking and sharing.

How to Combine Both Filtration and Search in the URL Parameters

In real-world applications, users often need to apply multiple filters or combine filtering with search functionality simultaneously.


Create a Combine Filter and Search Component

import React, { useEffect } from "react";
import { useSearchParams } from "react-router";
import { products } from "../productData";
import { Product } from "../types";

export default function AdvancedFiltering() {
//Initialize useSearchParams hook
const [searchParams, setSearchParams] = useSearchParams();

// Extract multiple parameters from URL
const category = searchParams.get("category") || "all";

const query = searchParams.get("query") || "";

const sortBy = searchParams.get("sort") || "name";

const [filteredProducts, setFilteredProducts] = React.useState<Product[]>([]);

// Apply all filters and sorting whenever parameters change
useEffect(() => {
let result = [...products];

// Apply category filter
if (category !== "all") {
result = result.filter((product) => product.category === category);
}

// Apply search query
if (query) {
result = result.filter((product) =>
product.name.toLowerCase().includes(query.toLowerCase())
);
}

// Apply sorting
result.sort((a, b) => {
if (sortBy === "price-low") {
return a.price - b.price;
} else if (sortBy === "price-high") {
return b.price - a.price;
} else {
return a.name.localeCompare(b.name);
}
});

setFilteredProducts(result);
}, [category, query, sortBy]);

// Update a single parameter while preserving others

const updateParams = (paramName: string, value: string) => {
const current = Object.fromEntries(searchParams.entries());
setSearchParams({
...current,
[paramName]: value,
});
};

return (
<div className="advanced-filtering">
<h2>Advanced Product Filtering</h2>

<div className="filter-controls">

<div className="filter-group">
<label>
Category:
<select
value={category}
onChange={(e) => updateParams("category", e.target.value)}
>
<option value="all">All Products</option>
<option value="phones">Phones</option>
<option value="laptops">Laptops</option>
</select>
</label>
</div>

<div className="filter-group">
<label>
Search:
<input
type="text"
value={query}
onChange={(e) => updateParams("query", e.target.value)}
placeholder="Enter product name..."
/>
</label>
</div>

<div className="filter-group">
<label>
Sort by:
<select
value={sortBy}
onChange={(e) => updateParams("sort", e.target.value)}
>
<option value="name">Name (A-Z)</option>
<option value="price-low">Price (Low to High)</option>
<option value="price-high">Price (High to Low)</option>
</select>
</label>
</div>
</div>

<div className="filter-summary">
<h3>
{filteredProducts.length} Products Found
{category !== "all" && ` in ${category}`}
{query && ` matching "${query}"`}
{sortBy !== "name" && ` sorted by ${sortBy}`}
</h3>
</div>

<div className="product-grid">
{filteredProducts.map((product, index) => (
<div key={index} className="product-card">
<h4>{product.name}</h4>
<p>{product.desc}</p>
<p>Price: ${product.price}</p>
<p>Category: {product.category}</p>
</div>
))}
</div>
</div>
);
}

This advanced implementation demonstrates:

1. Managing multiple URL search parameters simultaneously

2. Preserving existing parameters when updating just one

3. Applying multiple filters and sorting options to the dataset

4. Generating a human-readable summary of applied filters


This approach creates a powerful, user-friendly filtering system where all filter states are preserved in the URL.

The Best Practices for Managing URL Query Parameters.

These practices ensure optimal performance, user experience, and code maintainability:

1. Avoid Overloading the URL, only store essential state parameters.

The URL should contain parameters that:

- Define the primary content being displayed

- Represent user-initiated filters, searches, or sorting preferences and the URL Need to be shareable or bookmarkable.


2. Combine with State Management

For complex applications, consider a hybrid approach by using persistent and shareable states (filters, search queries, pagination).


You can use state management solutions (Redux, Context API) for global application state. This creates a separation that results in cleaner code and better performance.


3. Implement Debouncing for Real-Time Updates.

When updating URL parameters in response to user input (like typing in a search box), implement debouncing to prevent excessive updates:


import { useEffect, useState } from "react";
import { useSearchParams } from "react-router";
import debounce from "lodash.debounce";

function SearchWithDebounce() {
const [searchParams, setSearchParams] = useSearchParams();

const [inputValue, setInputValue] = useState(searchParams.get("q") || "");

// Create a debounced function
const debouncedSetParams = debounce((value) => {
if (value) {
setSearchParams({ q: value });
} else {
setSearchParams({});
}
}, 300);

// Update the responsive UI
const handleChange = (e) => {
const value = e.target.value;
setInputValue(value);
debouncedSetParams(value);
};

return (
<input
type="text"
value={inputValue}
onChange={handleChange}
placeholder="Search..."
/>
);
}

This approach maintains a responsive UI while preventing unnecessary URL updates during rapid typing.


4. Implement Error Handling for Invalid Parameters.

Always validate URL parameters and provide graceful fallbacks:

const page = searchParams.get("page");
const validPage = page && /^\d+$/.test(page) ?parseInt(page, 10) : 1;

const sortField = searchParams.get("sort");

const validSortFields = ["name", "price", "date"];

const validSort = sortField && validSortFields.includes(sortField)?sortField: "name";

This prevents application crashes or unexpected behavior when users manually edit or share malformed URLs.

Performance Optimization Techniques.

When implementing URL search parameters, consider these optimization strategies:

1. Memoize Filtered Results

Use React's useMemo to prevent unnecessary recalculations:

const filteredProducts = React.useMemo(() => {
return products.filter(product => {

if (category !== "all" && product.category !== category) return false;

if (query && !product.name.toLowerCase().includes(query.toLowerCase())) return false;
return true;
});
}, [products, category, query]);

2. Batch Parameter Updates

When multiple parameters need to change simultaneously, update them in a single operation:

// Instead of multiple updates:

setSearchParams({ ...Object.fromEntries(searchParams), category: "phones" });
setSearchParams({ ...Object.fromEntries(searchParams), sort: "price-low" });

// Use a single update:
setSearchParams({
...Object.fromEntries(searchParams),
category: "phones",
sort: "price-low"
});

3. Lazy Load Data Based on Parameters

For large datasets, consider fetching data based on the current URL parameters:

useEffect(() => {
const fetchData = async () => {
const category = searchParams.get("category") || "all";
const query = searchParams.get("query") || "";

setLoading(true);
try {
const response = await api.getProducts({ category, query });
setProducts(response.data);
} catch (error) {
setError("Failed to load products");
} finally {
setLoading(false);
}
};

fetchData();
}, [searchParams]);

This approach improves performance by only loading the data needed for the current view.

Conclusion

URL search parameters are a powerful tool in the modern web developer's arsenal, especially when building React applications. By leveraging the useSearchParams hook from React Router, you can create dynamic, user-friendly experiences that allow for seamless navigation, sharing, and bookmarking of specific application states.


Throughout this guide, we've explored:

- The fundamental importance of URL parameters in enhancing user experience

- Practical implementations of filtering and search functionality

- Advanced techniques for combining multiple parameters

- Best practices for clean, maintainable code

- Performance optimization strategies


By implementing these techniques in your React applications, you'll create more intuitive, shareable, and user-friendly interfaces that stand out from the competition.


Remember that URL parameters are just one piece of the puzzle. For a complete solution, consider how they integrate with your state management approach, API calls, and overall application architecture. When implemented thoughtfully, URL search parameters can significantly enhance your application's usability while maintaining clean, maintainable code.


Start integrating useSearchParams in your React projects today and elevate your user experience to the next level!


Please Share

You may also like