Next.js Discord

Discord Forum

NextJS 16 async layout with cache components

Unanswered
Thunder posted this in #help-forum
Open in Discord
Hi, when cache components is enabled , each async component needs to be wrapped with Suspense to enable streaming.
But in the root layout , we need for example to get the lang from a cookie in order to set the lang attribute of the html element.
How to solve this?

37 Replies

because the root layout should return html element and body element.
for example :

export default async function RootLayout() {
const locale = (await cookies()).get("locale")

return (<html lang={locale}>
.....
@Thunder because the root layout should return html element and body element. for example : export default async function RootLayout() { const locale = (await cookies()).get("locale") return (<html lang={locale}> .....
i havent tried this but is it possible to do:

export function HTML(props: { children: ReactNode }) {
  return <Suspense fallback={<html>{props.children}</html>}>
    <HTMLInner>
      {props.children}
    </HTMLInner>
  </Suspense>
}

async function HTMLInner(props: { children: ReactNode }) {
  const locale = (await cookies()).get("locale")
  return <html lang="locale">{props.children}</html>
}

?
Well, I am not sure, since the children is a page and that might be an async component it self, so we end up with an async component in the fallback it self.
I dont think this is the correct way to handle this case.
I am interested more in how NextJs team recommends to handle this case.
im not sure how that is a problem
if it doesn't work try wrapping the entire thing with a top-level Suspense. Im not sure if top-level loading.js could work
but loading.js would mean that you get 0 SEO and make the entire thing suspended
The question is, is the fallback designed to be an async component?
Also this have 2 problems when I tested it:
It causes the children to render twice.
And it delays the first render untill children return data.
ah thanks for testing it
loading.js is for the page not the layout, right ?
I didnt test, but it will , once in the suspense fallback and once in the suspense children since in the example you provided the children are passed to the fallback component
how do you know it will?
Do you know how suspense work ?
i assume so. it is just promises
if you put it in 5 places, doesn't mean it will run 5 times
It should
Try it out
I did. i can't reproduce it. Im wondering how you did it.
@Thunder It should
do you know how promises work ?
Suspense will call the fallback function, and throw its children promise, then it catches the children promise and await it, when it resolves it will switch the fallback function results with the promise results.
This means , if you pass the same component to the fallback and the suspense children, it will call it twice
If your children takes 1 second to load, then yes the page will take 1 second to load no matter what.

which is why try using <Suspense> without fallback instead.
but children will always be run once. you are passing the promise of the component. not the result. it is only being awaited once
@Thunder Suspense will call the fallback function, and throw its children promise, then it catches the children promise and await it, when it resolves it will switch the fallback function results with the promise results.
isnt it the other way around?

Suspense will call the children promise, while it is waiting, it shows the fallback element.

and fallback is an Element props? not a function? therefore it wont be "called" but only replaced
Have you done testing to back your claims? I really can't reproduce how my explanation can result in children being rendered twice :/
const promise = page()

await promise
await promise
await promise

// page will only run once
I know you are trying to help and thank you!.
But I would like to know what is the recommended way to handle this very common case without workarounds and tricks.
I would recommend going to GitHub discussions or Reddit thread
It is not a workaround and tricks. it is just how suspense works ?
Its not as easy as you think because with cacheComponents, the mental model is suggesting you to write dynamic API as deep in the Component Tree as possible.
or you know, dont use cacheComponent since cacheComponents forces you to have a static-root which umm you're trying to access cookies() at the top level
In the example you provided, if you have console log in the root page, and you navigate to it, how many times it logs ?
as ive said many times, once
Ok, thank you