Skip to content

Instantly share code, notes, and snippets.

@clarkmcc
Created May 3, 2022 14:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save clarkmcc/eba3f9c7ee2446afb637717ce805dcc5 to your computer and use it in GitHub Desktop.
Save clarkmcc/eba3f9c7ee2446afb637717ce805dcc5 to your computer and use it in GitHub Desktop.
A React hook to store and retrieve JSON values to the query parameters using React Router v6
import { useSearchParams } from "react-router-dom";
import { useCallback, useEffect } from "react";
import { isFunction } from "lodash";
/**
* Setter represents a type that can be passed to the setter function returned
* from this hook. It can either accept a value to set, or a callback function
* with access to the current value.
*
* @example
* setter(true)
* setter(current => !current)
*/
type Setter<T> = T | ((current: T) => T);
/**
* This custom hook provides an API for saving and retrieving values to the query
* parameters. It can be used *almost* as a drop in replacement for the useState
* hook, but does require you to name the query parameter key for your values.
*
* @example
* const [counter, setCounter] = useQueryParams("myCounter", 0)
*
* useEffect(() => {
* setCounter(current => current + 1)
* }, [])
*
* <span>{counter}</span>
*
* @param {string} name - The name of the query parameter. This will uniquely
* identify the key of the value in the query parameters.
* @param {T} initialValue - The initial value of the query parameter.
*/
export function useQueryParams<T>(
name: string,
initialValue?: T
): [T, (setter: Setter<T>) => void] {
const [params, setParams] = useSearchParams();
const get = useCallback<() => T>((): T => {
return JSON.parse(params.get(name));
}, [params]);
const set = useCallback(
(value: Setter<T>) => {
let newValue;
if (isFunction(value)) {
newValue = value(get());
} else {
newValue = value;
}
params.set(name, JSON.stringify(newValue));
setParams(params, {
replace: true,
});
},
[params, get]
);
/**
* On initialization, set the initial value
*/
useEffect(() => {
const currentValue = get();
if (initialValue != null && !currentValue) {
set(() => initialValue);
}
}, []);
return [get(), set];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment