How to Use Url Query as State in React
Updated at November 2023
For this blog I wanted people to be able to search for articles and store the state in the url query.
React does not provide a hook for this out of the box, so I came up with one that is framework-agnostic.
The hook looks like the following:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
import {useEffect, useState} from 'react';
type QueryParamType = string | number | boolean | readonly string[] | readonly number[] | readonly boolean[] | null;
function useQueryState<T extends QueryParamType>(queryKey: string, initialValue: T) {
const [state, setState] = useState<T>(initialValue);
useEffect(() => {
const getQueryParam = (key: string) => {
const params = new URLSearchParams(window.location.search);
return params.get(key);
};
const queryValue = getQueryParam(queryKey);
if (queryValue !== null) {
setState(queryValue as T);
} else {
const params = new URLSearchParams(window.location.search);
if (initialValue) {
params.set(queryKey, initialValue.toString());
const newUrl = `${window.location.pathname}?${params.toString()}`;
window.history.replaceState({}, '', newUrl);
}
}
}, [queryKey, initialValue]);
const updateState = (newValue: T) => {
setState(newValue);
const params = new URLSearchParams(window.location.search);
if (newValue) {
params.set(queryKey, newValue.toString());
} else {
params.delete(queryKey)
}
const newUrl = `${window.location.pathname}?${params.toString()}`;
window.history.replaceState({}, '', newUrl);
};
return [state, updateState] as const;
}
export default useQueryState;An example use case might be like this:
0
const [appliedFilter, setAppliedFilter] = useQueryState<string>('q', '')I am using this for my blog. It allows to filter the articles by title.