Maaz Khan
2 min readJul 26, 2024

In this post, I will introduce you to a custom React hook, useQueryState which you can think of as a useState hook with the additional capability of syncing with the query parameters of a URL. This would be very helpful if you’d like to keep the state across page reloads or share the state through the URL.

useQueryState Hook

import { Dispatch, SetStateAction, useEffect, useState } from "react";
import { useSearchParams } from "react-router-dom";

type UseQueryStateReturnType<T> = [T, Dispatch<SetStateAction<T>>];

const useQueryState = <T>(
param: string,
initialValue: T
): UseQueryStateReturnType<T> => {
const [searchParams, setSearchParams] = useSearchParams();

const paramValue = searchParams.get(param);
let parsedValue: T;
if (paramValue !== null) {
parsedValue = JSON.parse(paramValue) as T;
} else {
parsedValue = initialValue;
}

const [value, setValue] = useState<T>(parsedValue);

useEffect(() => {
setSearchParams((prev) => {
if (value !== null && value !== undefined && value !== "") {
prev.set(param, JSON.stringify(value));
} else prev.delete(param);
return prev;
});
}, [value]);

return [value, setValue];
};

export default useQueryState;

Usage
1.
Import useQueryState hook into your component

import useQueryState from "..../useQueryState";

2. Use within your component

 const [searchValue, setSearchValue] = useQueryState<string>("param", "");

Parameters
1. param (string): The name of the query parameter.
2. initialValue (T): The initial value, will be used when the query parameter is not present in the URL.

Return Value
An Array containing two items: current value and a setter function to update that value respectively

Example

import useQueryState from "..../useQueryState";

const Search = () => {
const [searchValue, setSearchValue] = useQueryState<string>("search", "");

return (
<div className="App">
<input
onChange={(e) => setSearchValue(e.target.value)}
value={searchValue}
placeholder="Search"
/>
<p>Search value is: {searchValue}</p>
</div>
);
};

export default Search;

In this example, the searchValue state is automatically synced with the search query parameter in the URL.

Demo

See the interactive codesandbox demo:

Working Explanation

The useQueryState hook utilizes the useSearchParams hook from react-router-dom to manage URL query parameters. Here’s a detailed breakdown of its functionality:

  1. Initial State Setup:
  • If a query parameter is present in the URL for the specified key, its value is parsed and used as the initial state.
  • If the query parameter is not present, the provided initial value is used.

2. State Synchronization:

  • Whenever the state changes, the corresponding query parameter in the URL is updated.
  • If the state is set to an empty string, null, or undefined, the query parameter is removed from the URL.

3. Stringify and Parsing:

  • Since URL query parameters can only store strings, non-string values are stringified before being stored.
  • When retrieving the value from the URL, it is parsed back to its original form before being used as the initial state.