Suspended component during server rendering blocks request instead of using fallback. v12.1.2+
See original GitHub issueVerify canary release
- I verified that the issue exists in Next.js canary release
Provide environment information
Operating System:
Platform: darwin
Arch: arm64
Version: Darwin Kernel Version 21.2.0: Sun Nov 28 20:28:41 PST 2021; root:xnu-8019.61.5~1/RELEASE_ARM64_T6000
Binaries:
Node: 16.14.2
npm: 8.1.4
Yarn: 1.22.1
pnpm: 6.32.4
Relevant packages:
next: 12.1.6-canary.12
react: 18.1.0
react-dom: 18.1.0
Describe the Bug
Prior to Next.js v12.1.2, throwing a promise during server rendering that never resolves resulted in the suspense fallback being rendered on the server. But now that results in the request never completing and next build
never resolving.
All users of react-query + suspense, including all Blitz.js based apps, rely on that previous behavior. In the case of react-query, you usually want client-side data fetching, so you need the suspense fallback loading screen to be rendered on the server. Then on the client, the suspense fallback will continue to render until the data is loaded client side.
This is the PR that changed this: https://github.com/vercel/next.js/pull/35490
Expected Behavior
I’m not sure if this new behavior is a bug or is intended with the new streaming rendering things.
Either way, it’s critical for us to have a way to opt into the previous behavior. One idea is a special flag to set on the thrown promise that would tell next.js/react to immediately render the fallback.
Example
const promise = new Promise(()=>{})
promise.reactForceFallback = true
throw promise
To Reproduce
Demo with latest nextjs version. The page never renders because it’s stuck in server rendering. https://codesandbox.io/s/divine-glitter-n07pnb?file=/pages/index.js
import { Suspense } from "react";
function Thing() {
if (typeof window === "undefined") {
throw new Promise(() => {});
}
return "Thing";
}
export default function IndexPage() {
return (
<div>
<p>Next.js Example</p>
<Suspense fallback="Loading...">
<Thing />
</Suspense>
</div>
);
}
Update: Throwing an error on the server instead of a promise causes the fallback to be rendered correctly, but then we get a flash of unstyled content on the client
import { Suspense } from "react";
function Thing() {
if (typeof window === "undefined") {
const e = new Error()
e.name = "Rendering Suspense fallback..."
delete e.stack
throw e
}
return "Thing";
}
export default function IndexPage() {
return (
<div>
<p>Next.js Example</p>
<Suspense fallback="Loading...">
<Thing />
</Suspense>
</div>
);
}
If you downgrade nextjs to 12.1.1, then you’ll see the loading indicator flash before the “Thing” text is rendered.
Issue Analytics
- State:
- Created a year ago
- Reactions:1
- Comments:6 (5 by maintainers)
Top GitHub Comments
I talked with @acdlite this week and they are adding an API to React within 2-3 weeks for forcing rendering of suspense fallback on the server without throwing an error. This will the proper solution to my original need.
This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.