Created
January 1, 2021 18:11
-
-
Save cvan/e84a8a707f5f7e5a039cbb5158b91195 to your computer and use it in GitHub Desktop.
next.js dynamic routes wait for hydration to complete
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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