Managing query parameters in a React application can be challenging, especially when you need to synchronize them with your component's state.
React Router provides hooks like useLocation
and useSearchParams
to help with this, but managing them together can still be complex.
In this blog post, we'll introduce an enhanced custom hook, useQueryParams, that simplifies the management of query parameters and adds a new feature to remove query parameters from the URL.
Introducing useQueryParams
Custom Hook
The useQueryParams
custom hook combines the functionality of useLocation, useSearchParams, and adds the ability to manage query parameters more effectively. It provides four main functionalities:
- Accessing All Query Parameters: Easily access all query parameters and their values as an object.
- Accessing a Specific Query Parameter: Get the value of a specific query parameter by its key.
- Updating Query Parameters: Update the value of a query parameter, which automatically updates the browser's URL.
- Removing Query Parameters: Remove a query parameter from the URL by its key.
Hook Implementation:
Create a useQueryParams.ts
file in src/hooks
folder:
import { useEffect, useState } from "react";
import { useLocation, useSearchParams } from "react-router-dom";
export default function useQueryParams() {
const location = useLocation();
const [searchParams, setSearchParams] = useSearchParams();
const [allQueryParams, setAllQueryParams] = useState(Object.fromEntries(searchParams));
useEffect(() => {
setAllQueryParams(Object.fromEntries(searchParams));
}, [searchParams]);
const getQueryParamByKey = (key: string) => {
const params = new URLSearchParams(location.search);
return params.get(key) || "";
};
const setQueryParam = (key :string, value: string) => {
const params = new URLSearchParams(location.search);
params.set(key, value.toString());
setSearchParams(params.toString());
};
const removeQueryParamByKey = (key: string) => {
const params = new URLSearchParams(location.search);
params.delete(key);
setSearchParams(params.toString());
};
return {
allQueryParams,
getQueryParamByKey,
setQueryParam,
removeQueryParamByKey,
};
}
How to Use useQueryParams
Hook
To use the useQueryParams
hook, follow these steps:
- Import the Hook:
import useQueryParams from './hooks/useQueryParams';
- Accessing All Query Parameters:
const { allQueryParams } = useQueryParams();
This gives you an object containing all query parameters and their values.
- Accessing a Specific Query Parameter:
const searchTerm = getQueryParamByKey('search');
const currentPage = getQueryParamByKey('page');
This retrieves the value of a specific query parameter by its key.
- Updating Query Parameters:
setQueryParam('search', 'react hooks');
setQueryParam('page', 2);
This updates the value of a query parameter, which will reflect in the browser's URL.
- Removing Query Parameters:
removeQueryParamByKey('page');
This removes the page query parameter from the URL.
Example Usage
Here's a simple example demonstrating the usage of the useQueryParams
hook in a React component:
App.tsx
import { ChangeEvent, useEffect, useState } from 'react';
import useQueryParams from './hooks/useQueryParams';
function App() {
const { allQueryParams, getQueryParamByKey, setQueryParam, removeQueryParamByKey } =
useQueryParams();
const [input, setInput] = useState<string>(getQueryParamByKey('search'));
const [page, setPage] = useState<number>(Number(getQueryParamByKey('page')));
useEffect(() => {
setQueryParam('search', input);
}, [input]);
useEffect(() => {
setQueryParam('page', page.toString());
}, [page]);
return (
<div>
<h1>All Query Params:</h1>
<pre>{JSON.stringify(allQueryParams)}</pre>
<h1>Query Param by Key:</h1>
<span>Search Box : </span>
<input
type="text"
value={input}
onChange={(event: ChangeEvent<HTMLInputElement>) => {
setInput(event.target.value);
}}
/>
<div>
<button
onClick={() => {
page > 0 && setPage(page - 1);
}}
>
{'<'}
</button>
<span> Current Page: {getQueryParamByKey('page')} </span>
<button
onClick={() => {
setPage(page + 1);
}}
>
{'>'}
</button>
</div>
<h1> Remove query param </h1>
<button
onClick={() => {
removeQueryParamByKey('page')
}}
>Revome page
</button>
<button
onClick={() => {
removeQueryParamByKey('search')
}}
>Remove search
</button>
</div>
);
}
export default App;
To use the useQueryParams
custom hook with React Router, make sure you wrap your application in a BrowserRouter
component. This is required for the useLocation
and useSearchParams
hooks to work correctly. Here's how you can add the BrowserRouter to your application:
main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.tsx';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<BrowserRouter>
<Routes>
<Route path={'/'} element={<App />} />
</Routes>
</BrowserRouter>
</React.StrictMode>
);
Conclusion
Managing query parameters in a React application can be simplified with the useQueryParams
custom hook. By encapsulating the logic for accessing, updating, and removing query parameters, this hook provides a cleaner and more maintainable approach to handling query parameters in your React components. Try it out in your next project and streamline your query parameter management!
Happy Coding 😊!
Top comments (4)
What if the query parameter is mispelled or not found in the current URL? It would be great to have an optional fallback value as it may increase the size of the code to create a condition inside the useState just for this check.
Also, you could have saved some typings by using a useMemo instead of a useState + useEffect.
We could turn this code into the following.
Hello @aminnairi
Yes, you can make your custom hook more readable and efficient by using
useMemo
instead ofuseState
+useEffect
and by adding an optional fallback value for the query parameters. Here's how to apply these recommendations:Adding Optional Fallback Value:
By adding a second parameter to the
getQueryParamByKey
method, you may offer an extra fallback value for query parameters. If the query parameter is misspelled or cannot be located, the fallback value will be sent back.Here's the updated
getQueryParamByKey
function:Now, you can provide a fallback value when calling
getQueryParamByKey
:Using useMemo for Efficiency:
To use useMemo instead of
useState
+useEffect
for initializingallQueryParams
, you can do the following:By incorporating these changes, your custom hook will be more efficient and flexible.
Great, but I find the code a bit long. You can try RTK Query + useMemo.
Hello @skipperhoa
Thank you for your suggestion!
I agree that using RTK Query and useMemo can be a great optimization, especially for larger applications.
However, for beginners, I've opted for a simpler approach using useState and useEffect to manage query parameters. This approach is more beginner-friendly and easier to understand, making it a great starting point for those new to React development.
Feel free to modify the code as needed for your own projects!