How to Use Url Query as State in React

Updated

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:

0import {useEffect, useState} from 'react';
1
2type QueryParamType = string | number | boolean | readonly string[] | readonly number[] | readonly boolean[] | null;
3
4function useQueryState<T extends QueryParamType>(queryKey: string, initialValue: T) {
5    const [state, setState] = useState<T>(initialValue);
6
7    useEffect(() => {
8        const getQueryParam = (key: string) => {
9            const params = new URLSearchParams(window.location.search);
10            return params.get(key);
11        };
12
13        const queryValue = getQueryParam(queryKey);
14
15        if (queryValue !== null) {
16            setState(queryValue as T);
17        } else {
18            const params = new URLSearchParams(window.location.search);
19            if (initialValue) {
20                params.set(queryKey, initialValue.toString());
21                const newUrl = `${window.location.pathname}?${params.toString()}`;
22                window.history.replaceState({}, '', newUrl);
23            }
24        }
25    }, [queryKey, initialValue]);
26
27    const updateState = (newValue: T) => {
28        setState(newValue);
29
30        const params = new URLSearchParams(window.location.search);
31        if (newValue) {
32            params.set(queryKey, newValue.toString());
33        } else {
34            params.delete(queryKey)
35        }
36        const newUrl = `${window.location.pathname}?${params.toString()}`;
37        window.history.replaceState({}, '', newUrl);
38    };
39
40    return [state, updateState] as const;
41}
42
43export default useQueryState;

An example use case might be like this:

0typescript
1const [appliedFilter, setAppliedFilter] = useQueryState<string>('q', '')

I am using this for my blog. It allows to filter the articles by title.