next.js
next.js copied to clipboard
Just calling `useSearchParams` hook in a client component breaks static page rendering of whole app (breaks static generation of meta tags)
Verify canary release
- [X] I verified that the issue exists in the latest Next.js canary release
Provide environment information
npx --no-install next info
Operating System:
Platform: darwin
Arch: arm64
Version: Darwin Kernel Version 22.4.0: Mon Mar 6 21:00:41 PST 2023; root:xnu-8796.101.5~3/RELEASE_ARM64_T8103
Binaries:
Node: 18.9.1
npm: 8.19.1
Yarn: 1.22.19
pnpm: N/A
Relevant packages:
next: 13.3.1-canary.6
eslint-config-next: 13.2.4
react: 18.2.0
react-dom: 18.2.0
Which area(s) of Next.js are affected? (leave empty if unsure)
App directory (appDir: true), Metadata (metadata, generateMetadata, next/head, head.js)
Link to the code that reproduces this issue
https://github.com/tmaihoff/next-metadata-issue
To Reproduce
This is my layout.tsx
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<ClientComponent />
<body>{children}</body>
</html>
)
}
How to break static generation with useSearchParams
This is my ClientComponent breaking the static generation.
export default function ClientComponent() {
const searchParams = useSearchParams();
return (
<div>
<h1>ClientComponent </h1>
<p>searchParams: {searchParams.toString()}</p>
</div>
)
}
With the above ClientComponent, the generated index.html looks like this.
You can see that the <meta> tags are missing inside <head>. However they are present in <script>self.__next_f.push([1,'3: ...
<!DOCTYPE html>
<html id="__next_error__">
<head>
<script
src="/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"
nomodule=""
></script>
</head>
<body>
<script
src="/_next/static/chunks/webpack-057ba9cde9392c2a.js"
async=""
></script>
<script
src="/_next/static/chunks/455-e3a12aac2a978f1a.js"
async=""
></script>
<script
src="/_next/static/chunks/main-app-adc18e92199e3750.js"
async=""
></script>
</body>
</html>
<script>
(self.__next_f = self.__next_f || []).push([0]);
</script>
<script>
self.__next_f.push([1, '0:"$L1"\n']);
</script>
<script>
self.__next_f.push([
1,
'2:I{"id":"611","chunks":["272:webpack-057ba9cde9392c2a","455:455-e3a12aac2a978f1a"],"name":"","async":false}\n4:I{"id":"8331","chunks":["272:webpack-057ba9cde9392c2a","455:455-e3a12aac2a978f1a"],"name":"","async":false}\n5:I{"id":"847","chunks":["185:app/layout-ef8499614f6208b4"],"name":"","async":false}\n6:I{"id":"8892","chunks":["272:webpack-057ba9cde9392c2a","455:455-e3a12aac2a978f1a"],"name":"","async":false}\n7:I{"id":"8880","chunks":["272:webpack-057ba9cde9392c2a","455:455-e3a12aac2a978f1a"],"name":"","as',
]);
</script>
<script>
self.__next_f.push([
1,
'ync":false}\n8:I{"id":"7059","chunks":["931:app/page-0e5774f4785aa9aa"],"name":"","async":false}\n',
]);
</script>
<script>
self.__next_f.push([
1,
'1:["$","$L2",null,{"assetPrefix":"","initialCanonicalUrl":"/","initialTree":["",{"children":["",{}]},null,null,true],"initialHead":["$L3",null],"globalErrorComponent":"$4","children":[["$","html",null,{"lang":"en","children":[["$","$L5",null,{}],["$","body",null,{"children":["$","$L6",null,{"parallelRouterKey":"children","segmentPath":["children"],"hasLoading":false,"template":["$","$L7",null,{}],"notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\\"Segoe UI\\",Roboto,Helvetica,Arial,sans-serif,\\"Apple Color Emoji\\",\\"Segoe UI Emoji\\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"childProp":{"current":[["$","main",null,{"className":"page_main__ibFHK","children":[["$","div",null,{"className":"page_description__s_Lqk","children":[["$","p",null,{"children":["Get started by editing ",["$","code",null,{"className":"page_code__Cdcue","children":"src/app/page.tsx"}]]}],["$","div",null,{"children":["$","a",null,{"href":"https://vercel.com?utm_source=create-next-app\u0026utm_medium=appdir-template\u0026utm_campaign=create-next-app","target":"_blank","rel":"noopener noreferrer","children":["By"," ",["$","$L8",null,{"src":"/vercel.svg","alt":"Vercel Logo","className":"page_vercelLogo__1QD2W","width":100,"height":24,"priority":true}]]}]}]]}],["$","div",null,{"className":"page_center__GvJ9Y","children":[["$","$L8",null,{"className":"page_logo__M5piD","src":"/next.svg","alt":"Next.js Logo","width":180,"height":37,"priority":true}],["$","div",null,{"className":"page_thirteen__DLEbK","children":["$","$L8",null,{"src":"/thirteen.svg","alt":"13","width":40,"height":31,"priority":true}]}]]}],["$","div",null,{"className":"page_grid__2WZXq","children":[["$","a",null,{"href":"https://beta.nextjs.org/docs?utm_source=create-next-app\u0026utm_medium=appdir-template\u0026utm_campaign=create-next-app","className":"page_card__ftWzl","target":"_blank","rel":"noopener noreferrer","children":[["$","h2",null,{"className":"__className_e7970e","children":["Docs ",["$","span",null,{"children":"-\u003e"}]]}],["$","p",null,{"className":"__className_e7970e","children":"Find in-depth information about Next.js features and API."}]]}],["$","a",null,{"href":"https://vercel.com/templates?framework=next.js\u0026utm_source=create-next-app\u0026utm_medium=appdir-template\u0026utm_campaign=create-next-app","className":"page_card__ftWzl","target":"_blank","rel":"noopener noreferrer","children":[["$","h2",null,{"className":"__className_e7970e","children":["Templates ",["$","span",null,{"children":"-\u003e"}]]}],["$","p",null,{"className":"__className_e7970e","children":"Explore the Next.js 13 playground."}]]}],["$","a",null,{"href":"https://vercel.com/new?utm_source=create-next-app\u0026utm_medium=appdir-template\u0026utm_campaign=create-next-app","className":"page_card__ftWzl","target":"_blank","rel":"noopener noreferrer","children":[["$","h2",null,{"className":"__className_e7970e","children":["Deploy ",["$","span",null,{"children":"-\u003e"}]]}],["$","p",null,{"className":"__className_e7970e","children":"Instantly deploy your Next.js site to a shareable URL with Vercel."}]]}]]}]]}],null,null,[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/ffa6367fdf432817.css","precedence":"next.js"}],["$","link","1",{"rel":"stylesheet","href":"/_next/static/css/e5c2b8b025a6a123.css","precedence":"next.js"}]]],"segment":""}}]}]]}],null,null,[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/876d048b5dab7c28.css","precedence":"next.js"}]]]}]\n',
]);
</script>
<script>
self.__next_f.push([
1,
'3:[[["$","meta",null,{"charSet":"utf-8"}],["$","title",null,{"children":"Create Next App"}],["$","meta",null,{"name":"description","content":"Generated by create next app"}],null,null,null,null,null,null,null,null,["$","meta",null,{"name":"viewport","content":"width=device-width, initial-scale=1"}],null,null,null,null,null,null,null,null,null,null,[]],[null,null,null,null],null,null,[null,null,null,null,null],null,[null,["$","meta",null,{"property":"og:title","content":"Create Next App"}],["$","meta",null,{"property":"og:description","content":"Generated by create next app"}],null,null,null,null,null,null,null,null,null,null,null,null,null],null,null,[null,[["$","link",null,{"rel":"icon","href":"/_next/static/media/metadata/favicon.603d046c.ico","type":"image/x-icon","sizes":"any"}]],[],null]]\n',
]);
</script>
How to fix it
Just removing the line useSearchParams from the ClientComponent does the trick.
Using this
export default function ClientComponent() {
return (
<div>
<h1>ClientComponent </h1>
</div>
)
}
results in the following index.html with statically generated <meta> tags:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link
rel="stylesheet"
href="/_next/static/css/ffa6367fdf432817.css"
data-precedence="next.js"
/>
<link
rel="stylesheet"
href="/_next/static/css/e5c2b8b025a6a123.css"
data-precedence="next.js"
/>
<link
rel="stylesheet"
href="/_next/static/css/876d048b5dab7c28.css"
data-precedence="next.js"
/>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta property="og:title" content="Create Next App" />
<meta property="og:description" content="Generated by create next app" />
...
Describe the Bug
Just using the useSearchParams hook in a client component breaks the static site rendering of the whole app.
This can be observed e.g. by the meta tags not being statically generated with npm run build.
Just removing the hook from the code makes the static generation work.
Please check the Reproduction example.
Expected Behavior
useSearchParams should not affect the static site generation of server components of the app.
Which browser are you using? (if relevant)
No response
How are you deploying your application? (if relevant)
No response
Wrap it in suspense, that should help. It's mentioned in beta docs for useSearchParams.
This bug appears also with usePathname and Suspense doesn't help. I can't reproduce it, but I check logs and sometime users see the __next_error__ page instead of correct page
Wrap it in suspense, that should help. It's mentioned in beta docs for useSearchParams.
For me it worked in Next 13.5.5.
i tried to fix with Suspense as in docs but didnt work in Next 14.1.0
same issue
Edit by maintainer bot: Comment was automatically minimized because it was considered unhelpful. (If you think this was by mistake, let us know). Please only comment if it adds context to the issue. If you want to express that you have the same problem, use the upvote 👍 on the issue description or subscribe to the issue for updates. Thanks!