Skip to content

Instantly share code, notes, and snippets.

@cvan
Created January 1, 2021 18:11
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 cvan/e84a8a707f5f7e5a039cbb5158b91195 to your computer and use it in GitHub Desktop.
Save cvan/e84a8a707f5f7e5a039cbb5158b91195 to your computer and use it in GitHub Desktop.
next.js dynamic routes wait for hydration to complete
import React, { useEffect, useState } from 'react';
import { withRouter } from 'next/router';
// @example `"/films/[slug]"`
const IS_DYNAMIC_ROUTE = urlPathname => String(urlPathname).includes('[');
// Usage in your dynamic-route components:
// @example
// export default withDynamicRoute(Page);
const withDynamicRouteHydrated = PageComponent => withRouter(({ router, ...props }) => {
// Temporary workaround for dynamic routes being mounted twice in the local-dev env.
// @see https://nextjs.org/docs/routing/dynamic-routes#caveats
// @see https://github.com/vercel/next.js/issues/17143#issuecomment-715409733
// @see https://github.com/vercel/next.js/discussions/11484#discussioncomment-2362
const shouldWaitForHydration = IS_DYNAMIC_ROUTE(router.pathname);
// On first mount, a dynamic route's initial `asPath` will be '"/films/[slug]"', and its `query` will be `{}`.
const [isReady, setIsReady] = useState(!shouldWaitForHydration);
useEffect(() => {
if (shouldWaitForHydration && !isReady) {
// We can infer hydration completion by checking that the router now contains the dynamic parameters.
// P.S. A new boolean, `router.isReady`, was recently added (2020/12/30).
// @see https://github.com/vercel/next.js/pull/20628/files
// It's recommended to use that when the canary TOT migrates to the next released version.
if (Object.keys(router.query).length) {
// The dynamic route's `asPath` will be `"/films/cary-grant-comedies"`, and its `query` will be `{slug: "cary-grant-comedies"}`.
setIsReady(true);
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return isReady ? <PageComponent router={router} {...props} /> : null;
});
export default withDynamicRouteHydrated;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment