Programmatically Updating Query Parameters in React Router
Query parameters, also known as URL search parameters, are key-value pairs appended to a URL after a question mark (?
). They are used to pass additional information to a web page without affecting the path itself. For instance, in the URL https://www.example.com/products?category=electronics&sort=price
, the query parameters are category=electronics
and sort=price
.
Updating Query Parameters Programmatically
React Router provides a convenient hook called useNavigate
(or useHistory
in older versions) to manipulate the URL, including updating query parameters. Here's a step-by-step breakdown:
-
Import
useNavigate
:import { useNavigate } from 'react-router-dom';
-
Access Navigation Function:
Inside your React component, call the
useNavigate
hook to get a function that allows you to programmatically change the URL.const navigate = useNavigate();
-
Construct the New Query String:
- Use the
URLSearchParams
object (available in modern browsers) to create or modify the query string portion of the URL. - Set or modify key-value pairs as needed:
const newSearchParams = new URLSearchParams(window.location.search); newSearchParams.set('filter', 'active'); // Add a new parameter newSearchParams.delete('sort'); // Remove an existing parameter // ... modify other parameters
- Use the
-
Update the URL:
- Call the
navigate
function, passing an object with the updated search string:
navigate({ search: newSearchParams.toString() });
- Call the
Complete Example:
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
function ProductList() {
const [filter, setFilter] = useState('');
const navigate = useNavigate();
const handleFilterChange = (event) => {
setFilter(event.target.value);
};
const handleFilterSubmit = () => {
const newSearchParams = new URLSearchParams(window.location.search);
newSearchParams.set('filter', filter);
navigate({ search: newSearchParams.toString() });
};
return (
<div>
<select value={filter} onChange={handleFilterChange}>
<option value="">All Products</option>
<option value="active">Active Products</option>
{/* ... other options */}
</select>
<button onClick={handleFilterSubmit}>Filter</button>
</div>
);
}
export default ProductList;
In this example, selecting a filter option from the dropdown updates the filter
state variable. Clicking the "Filter" button triggers the handleFilterSubmit
function, which constructs the new query string with the selected filter and updates the URL using navigate
.
Additional Considerations:
- Remember that updating the URL triggers a re-render of the component at the new route, so handle state management accordingly.
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
function ProductList() {
const [filter, setFilter] = useState('');
const navigate = useNavigate();
const handleFilterChange = (event) => {
setFilter(event.target.value);
};
const handleFilterSubmit = () => {
const newSearchParams = new URLSearchParams(window.location.search);
newSearchParams.set('filter', filter); // Add or update the 'filter' parameter
navigate({ search: newSearchParams.toString() }); // Update URL with new search string
};
return (
<div>
<select value={filter} onChange={handleFilterChange}>
<option value="">All Products</option>
<option value="active">Active Products</option>
{/* ... other options */}
</select>
<button onClick={handleFilterSubmit}>Filter</button>
</div>
);
}
export default ProductList;
Explanation:
- Imports
useState
anduseNavigate
fromreact-router-dom
. - Uses state (
filter
) to store the selected filter value. handleFilterChange
updates the state based on the dropdown selection.handleFilterSubmit
constructs the new query string usingURLSearchParams
.- Sets or updates the
filter
parameter based on the selected value. - Calls
navigate
to update the URL with the new search string.
- Sets or updates the
Example 2: Adding or Removing Query Parameters on Button Click
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
function MyComponent() {
const [showDetails, setShowDetails] = useState(false);
const navigate = useNavigate();
const handleToggleDetails = () => {
const newSearchParams = new URLSearchParams(window.location.search);
if (showDetails) {
newSearchParams.delete('details'); // Remove 'details' parameter if present
} else {
newSearchParams.set('details', 'true'); // Add 'details' parameter
}
navigate({ search: newSearchParams.toString() });
setShowDetails(!showDetails); // Update state to reflect change
};
return (
<div>
<button onClick={handleToggleDetails}>
{showDetails ? 'Hide Details' : 'Show Details'}
</button>
</div>
);
}
export default MyComponent;
- Manages the
showDetails
state to track whether details are visible. handleToggleDetails
handles button clicks:- Creates a
URLSearchParams
object. - If
showDetails
is true, removes thedetails
parameter (hiding details). - If
showDetails
is false, adds thedetails
parameter with a value (showing details). - Updates the URL using
navigate
. - Toggles the
showDetails
state to reflect the change in button text.
- Creates a
Key Points:
- Use
URLSearchParams
for efficient query string manipulation. - Consider using libraries like
query-string
for advanced scenarios. - Update component state for UI changes based on query parameter updates.
- This hook provides a more concise way to interact with query parameters within your component.
- It returns an array containing two elements:
- The current
URLSearchParams
object representing the query string. - A setter function to update the search params.
- The current
import { useSearchParams } from 'react-router-dom';
function MyComponent() {
const [searchParams, setSearchParams] = useSearchParams();
const filter = searchParams.get('filter'); // Access existing parameter
const handleFilterChange = (newFilter) => {
setSearchParams({ filter: newFilter }); // Update single parameter
};
// ... other logic
}
history.push with Search String (Older React Router Versions)
- If you're using an older version of React Router (before v6), you can use
history.push
along with a constructed search string to update the URL.
import { useHistory } from 'react-router-dom';
function MyComponent() {
const history = useHistory();
const handleFilterChange = (newFilter) => {
const newSearchParams = new URLSearchParams(window.location.search);
newSearchParams.set('filter', newFilter);
history.push({ search: newSearchParams.toString() });
};
// ... other logic
}
Custom Hook (For Reusability)
- Create a reusable custom hook that encapsulates the logic for updating query params.
import { useNavigate } from 'react-router-dom';
function useUpdateQueryParams() {
const navigate = useNavigate();
const updateParams = (newParams) => {
const searchParams = new URLSearchParams(window.location.search);
Object.entries(newParams).forEach(([key, value]) => searchParams.set(key, value));
navigate({ search: searchParams.toString() });
};
return updateParams;
}
- Use this hook in your components for cleaner code:
import { useUpdateQueryParams } from './useUpdateQueryParams';
function MyComponent() {
const updateParams = useUpdateQueryParams();
const handleFilterChange = (newFilter) => {
updateParams({ filter: newFilter });
};
// ... other logic
}
Choosing the Right Method:
- If you're using React Router v6.4 or above,
useSearchParams
is the recommended approach for its simplicity. - For older versions or complex scenarios involving multiple parameter updates, consider a custom hook.
- Use
history.push
sparingly asuseNavigate
provides a more general way to handle navigation.
reactjs react-router