-
Notifications
You must be signed in to change notification settings - Fork 30k
Description
What is the documentation issue?
We've all seen this error:
Runtime data such as
cookies(),headers(),params, orsearchParamswas accessed outside of<Suspense>.
First, I want to say that I really like that Cache Components forces to find where you block unnecessarily. Given the reputation of App Router as being somehow slow, I think forcing to add Suspense boundaries does help in the sense that developers can see that it's their code is blocking, and have an opportunity to fix it.
However, this seems to make some common patterns impossible to express without warnings.
In particular, I'm interested in the pattern where the app's UI depends on whether you're logged in or not. A logged-in and logged-out states are significantly different in their nature so a <Suspense> boundary is not always adequate or appropriate, and it could not be determined before reading cookies() either.
Consider this UI from a website I use:
bla.mov
(They're using Next but I don't think they're using CC; I'm just using this example because it's illustrative)
Notice a placeholder in the piece of UI corresponding to the user avi. I personally hate when websites do that.
This kind of UX feels like a relic of the jamstack era when the client actually was unable to determine whether you're logged in or not and so it had to display a placeholder while figuring out. Many people who use Next don't actually want to do jamstack and are fine with running some code dynamically.
The problem is that this "jamstacky" UX pattern seems forced upon the developers by the Cache Components approach, even when there's no actual perf upside for the user. Reading cookies() and then deciding to display the avi (or not) does not necessarily need any expensive data roundtrip justifying sending a shell without it. In my opinion, for the kind of apps I built, the top bar (including the avi) should just be a part of the initial shell.
Workaround
I've recently learned that it's possible to work around the problem like this:
export default async function RootLayout({ children }: { children: React.ReactNode }) {
// Note: you might not want to copy this pattern (see explanation below)
return (
<Suspense fallback={null}>
<html lang="en">
<body>
...
</body>
</html>
</Suspense>
);
}Apparently, if Suspense is placed above the <html> tag, it will both shut up the Cache Components "runtime access" warning and prevent an incomplete first frame from showing up in the browser. This wasn't obvious though, and it's a bit nuclear — now I don't get any warnings about runtime access at all, not even for more nested pages where it would be valuable.
What I really want to express is: this specific bit of data (getting the session + profile info) is something I want to block the UI on and I do not want to place <Suspense> boundaries around, however I'd still appreciate warnings in other places.
Hope this is helpful!
Is there any context that might help us understand?
Does the docs page already exist? Please link to it.
No response