Skip to content

Instantly share code, notes, and snippets.

@tomfa
Created May 20, 2021 22:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tomfa/9bf850bbaeb421c77d2b1bd2a158ae10 to your computer and use it in GitHub Desktop.
Save tomfa/9bf850bbaeb421c77d2b1bd2a158ae10 to your computer and use it in GitHub Desktop.
NextJS string state in URL query param
import useQueryString from './useQueryString'
export const Component = () => {
const [cat, setCat] = useQueryString<string>({
key: 'cat',
defaultValue: 'Robert Paulson',
});
return <h1>His name is <strong>{cat}</strong></h1>
}
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useRouter } from 'next/router';
import { getQueryStringValue } from './utils.query';
interface Props {
key: string;
defaultValue: string;
}
function useQueryString({
key,
defaultValue,
}: Props): [string, React.Dispatch<React.SetStateAction<string>>] {
const router = useRouter();
const [loading, setLoading] = useState(false);
const [value, setValue] = useState<string>(() => {
const queryParamValue = getQueryStringValue(router, key);
return queryParamValue || defaultValue;
});
const onSetValue = useCallback(
async (newValue: string) => {
setLoading(true);
setValue(newValue);
// use router.push if you want to edit browser history
await router.replace({ query: { ...router.query, [key]: newValue } }, undefined, {
shallow: true,
});
setLoading(false);
},
[router, key],
);
const queryParamValue = router.query[key];
const queryParamMatches = useMemo(() => {
if (!router.isReady) {
return false;
}
if (!queryParamValue) {
const valueIsUndefinedAsQuery = value === undefined || value === defaultValue;
return valueIsUndefinedAsQuery;
}
return queryParamValue === value;
}, [value, queryParamValue, defaultValue, router.isReady]);
// Update value on url change
useEffect(() => {
if (!router.isReady || queryParamMatches || loading) {
return;
}
setValue(queryParamValue || defaultValue);
}, [setValue, queryParamMatches, defaultValue, queryParamValue router.isReady, loading]);
return [value, onSetValue];
}
export default useQueryString;
import qs from 'query-string'; // Note: added 3rd party lib
import { NextRouter } from 'next/router';
export const getQueryStringValue = (router: NextRouter, key: string) => {
if (router.isReady) {
return router.query[key];
}
if (typeof window !== 'undefined') {
const values = qs.parse(window.location.search);
return values[key];
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment