How to Keep Query Params While Navigating Using React Router
2 min readDec 28, 2024
One of the biggest problems when trying to code a user-friendly navigation experience in your web application is keeping the query params in the URL while navigating.
For example:
- You have a cross-query param, such as
language
. - You want to persist this query param throughout the entire user session.
- But if you use React Router, the query params are lost by default on every navigation.
https://www.mywebapp.com/blog?language=es_ES
# You move to the Home page but… 😢
https://www.mywebapp.com
# The query params are gone.
However, there might be parameters in the URL that you don’t want to persist on navigation. For example:
https://www.mywebapp.com/blog?language=es_ES&postId=2
# You move to the Home page, but you only want to persist the language param.
https://www.mywebapp.com/blog?language=es_ES
Keep Search Params with React Router
The solution is simple: you can create a custom hook that wraps the useNavigate
hook.
import { useNavigate, useSearchParams } from 'react-router-dom';
// Parameters to keep in the URL
const PARAMS_TO_KEEP = ['language'];
const useNavigateWithParams = () => {
const navigate = useNavigate();
const [searchParams] = useSearchParams();
const navigateWithParams = (path, options = {}) => {
// Filter the parameters we want to retain
const paramsToKeep = {};
PARAMS_TO_KEEP.forEach((param) => {
const value = searchParams.get(param);
if (value) {
paramsToKeep[param] = value;
}
});
// Build the new URL with the retained parameters
const url = new URL(path, window.location.origin);
Object.entries(paramsToKeep).forEach(([key, value]) => {
url.searchParams.set(key, value);
});
// Navigate to the new URL
navigate(`${url.pathname}${url.search}`, options);
};
return navigateWithParams;
};
export default useNavigateWithParams;
Typed Version in TypeScript
If you are using TypeScript, here’s a typed version of the hook:
import { useNavigate, useSearchParams, NavigateOptions } from 'react-router-dom';
// Parameters to keep in the URL
const PARAMS_TO_KEEP = ['language'];
const useNavigateWithParams = (): ((path: string, options?: NavigateOptions) => void) => {
const navigate = useNavigate();
const [searchParams] = useSearchParams();
const navigateWithParams = (path: string, options: NavigateOptions = {}): void => {
// Filter the parameters we want to retain
const paramsToKeep: Record<string, string> = {};
PARAMS_TO_KEEP.forEach((param) => {
const value = searchParams.get(param);
if (value) {
paramsToKeep[param] = value;
}
});
// Build the new URL with the retained parameters
const url = new URL(path, window.location.origin);
Object.entries(paramsToKeep).forEach(([key, value]) => {
url.searchParams.set(key, value);
});
// Navigate to the new URL
navigate(`${url.pathname}${url.search}`, options);
};
return navigateWithParams;
};
export default useNavigateWithParams;
I hope it was helpful. Keep coding!