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.