Skip to content

Instantly share code, notes, and snippets.

@intrnl
Last active January 14, 2023 00:37
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 intrnl/da3e3a07837cb2e93e52e62770a727d7 to your computer and use it in GitHub Desktop.
Save intrnl/da3e3a07837cb2e93e52e62770a727d7 to your computer and use it in GitHub Desktop.
React hook for managing search params with serialization (using react-router v6 and serialize-query-params)
import React, { type ReactNode } from 'react';
import { useSearchParams } from 'react-router-dom';
import { type QueryParamConfig } from 'serialize-query-params';
export * from 'serialize-query-params';
const SearchParamsContext = React.createContext<ReturnType<typeof useSearchParams> | null>(null);
interface SearchParamsProviderProps {
children?: ReactNode;
}
export const SearchParamsProvider = (props: SearchParamsProviderProps) => {
const tuple = useSearchParams();
return (
<SearchParamsContext.Provider value={tuple}>
{props.children}
</SearchParamsContext.Provider>
);
};
export const useSearchParam = <D, E>(name: string, config: QueryParamConfig<E, D>) => {
const [searchParams, setSearchParams] = React.useContext(SearchParamsContext)!;
const values = searchParams.getAll(name);
const decoded = React.useMemo(() => {
return config.decode(values) ?? undefined;
}, [values.join('\0')]);
const update = React.useCallback((next: E, replace?: boolean) => {
const nextSearchParams = new URLSearchParams(searchParams);
const encoded = config.encode(next);
if (encoded == null) {
nextSearchParams.delete(name);
} else if (Array.isArray(encoded)) {
nextSearchParams.delete(name);
for (const v of encoded) {
if (v == null) {
continue;
}
nextSearchParams.append(name, v);
}
} else {
nextSearchParams.set(name, encoded);
}
setSearchParams(nextSearchParams, { replace });
}, [searchParams]);
return [decoded, update] as const;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment