Effortlessly synchronizing a React component's state with URL search parameters can be a common requirement when working with React applications that utilize React Router. In such scenarios, the useQueryParamsState
hook provides an elegant solution, streamlining the management of URL query parameters.
Installation
To get started, ensure you have React and React Router installed in your project:
npm install react react-router-dom
'useQueryParamsState' hook
import { useState, useEffect, Dispatch, SetStateAction } from "react";
import { useLocation } from "react-router-dom";
type UseQueryParamsStateReturnType<T> = [T, Dispatch<SetStateAction<T>>];
export const useQueryParamsState = <T>(
param: string,
initialState: T
): UseQueryParamsStateReturnType<T> => {
const location = useLocation();
// State for managing the value derived from the query parameter
const [value, setValue] = useState<T>(() => {
if (typeof window === "undefined") return initialState;
// Parse query parameter value from the URL
const { search } = window.location;
const searchParams = new URLSearchParams(search);
const paramValue = searchParams.get(param);
return paramValue !== null ? JSON.parse(paramValue) as T : initialState;
});
useEffect(() => {
const currentSearchParams = new URLSearchParams(window.location.search);
// Update the query parameter with the current state value
if (value !== null && value !== "") {
currentSearchParams.set(param, JSON.stringify(value));
} else {
// Remove the query parameter if the value is null or empty
currentSearchParams.delete(param);
}
// Update the URL with the modified search parameters
const newUrl = [window.location.pathname, currentSearchParams.toString()]
.filter(Boolean)
.join("?");
// Update the browser's history without triggering a page reload
window.history.replaceState(window.history.state, "", newUrl);
}, [param, value, location.pathname]);
return [value, setValue];
};
Usage
- Import the
useQueryParamsState
hook into your component:
import { useQueryParamsState } from './path-to/useQueryParamsState';
- Use the hook within your component:
const MyComponent: React.FC = () => {
const [paramValue, setParamValue] = useQueryParamsState<string>('myQueryParam', 'default');
// Use paramValue and setParamValue as needed in your component
return (
// Your component JSX
);
Parameters
-
param
(string): The name of the query parameter you want to sync with the component state. -
initialState
(T): The initial state for the component. This will be used when the query parameter is not present in the URL.
Return Value
The hook returns a tuple containing the current value of the query parameter and a function to update that value.
type UseQueryParamsStateReturnType<T> = [T, Dispatch<SetStateAction<T>>];
Example
Consider a component that manages a search term based on a query parameter:
import { useQueryParamsState } from './path-to/useQueryParamsState';
const SearchComponent: React.FC = () => {
const [searchTerm, setSearchTerm] = useQueryParamsState<string>('search', '');
return (
<div>
<label>Search Term:</label>
<input
type="text"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
<p>Search Term: {searchTerm}</p>
</div>
);
};
In this example, the SearchComponent
automatically syncs its state with the 'search' query parameter in the URL, allowing users to bookmark or share specific search states.
Demo
Explore the interactive demo on CodeSandbox to see the useQueryParamsState
hook in action:
Explanation
The useQueryParamsState
hook leverages React's state and effect hooks along with React Router's useLocation
to manage the state of a specific query parameter. It handles parsing and updating the URL, providing a clean and reusable solution for components that need to interact with query parameters in a React Router environment. Developers can use this hook to create components that maintain their state based on URL query parameters without manually handling the complexities of URL manipulation.
Thanks For Reading 😉
Top comments (1)
Created a library for storing state in the url github.com/asmyshlyaev177/state-in...