Skip to content

Instantly share code, notes, and snippets.

@KATT
Last active August 5, 2022 20:48
Show Gist options
  • Save KATT/524a866021869affddf4be5754f2f672 to your computer and use it in GitHub Desktop.
Save KATT/524a866021869affddf4be5754f2f672 to your computer and use it in GitHub Desktop.
`useRouterQuery()` hook to get query params on first render
import { useRouter } from 'next/router';
import { useMemo } from 'react';
/**
* Ugly hack for using search params as `useRouter()` won't return it on first render
* @link https://gist.github.com/KATT/524a866021869affddf4be5754f2f672
*/
export function useRouterQuery() {
const router = useRouter();
const { asPath, query, pathname } = router;
const value = useMemo(() => {
// if we have query params from the router, let's return that
if (Object.keys(query).length > 0) {
return query;
}
// split path by `/` or `?`
const pathnameParts = pathname.split(/\/|\?/);
const loc =
typeof location !== 'undefined'
? {
query: Object.fromEntries(new URLSearchParams(location.search)),
pathname: location.pathname,
}
: {
query,
pathname: asPath,
};
const asPathParts = loc.pathname.split(/\/|\?/);
// actual query object that we wanna use
const actualQuery: typeof query = {};
for (let index = 0; index < pathnameParts.length; index++) {
const part = pathnameParts[index];
if (!part.startsWith('[') || !part.endsWith(']')) {
continue;
}
// extract real query param from `post/[id]` style routes
// removes first and last character
const key = part.slice(1, -1);
if (key.startsWith('...')) {
// catch-all route
const catchAllKey = key.slice(3);
actualQuery[catchAllKey] = asPathParts.splice(index);
break;
}
// append to "actual query"
actualQuery[key] = asPathParts[index];
}
for (const key in loc.query) {
actualQuery[key] = loc.query[key];
}
return actualQuery;
}, [asPath, query, pathname]);
return value;
}
// Next.js apge
import { useRouterQuery } from '../lib/useRouterQuery';
export default function MyPage(props: inferSSRProps<typeof getStaticProps>) {
const searchParams = useRouterQuery();
const username = (props.username || searchParams.username) as string;
// now `username` is always a string on first render
}
export const getStaticPaths: GetStaticPaths = async () => {
return {
paths: [],
fallback: true,
};
};
export async function getStaticProps(context: GetStaticPropsContext<{ username: string }>) {
const username = context.params!.username;
return {
props: {
username,
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment