Deviopath › Next.js

Streaming with use() and Suspense

Hard · Streaming

React 19's use(promise) reads the value of a Promise during render. If the Promise is still pending, the component suspends and the nearest <Suspense fallback> is shown until it resolves. In Next.js this is how streaming works: a Server Component starts a fetch without awaiting it, passes the Promise to a Client Component, and the page streams the fallback first and the content later (loading.tsx is a Suspense boundary around the page).

Here the Promise is created on the client (a simplification): fetchPosts(version) in the starter resolves after 80 ms to { version, posts }.

- PostList calls use(promise) and renders <p className="loaded">Loaded version N</p> plus the post titles as <li> in <ul className="posts">. Posts with draft: true are hidden unless the checkbox <input type="checkbox" className="drafts"> (Show drafts) is checked.

- Wrap it in <Suspense fallback={<p className="fallback">Loading posts…</p>}>.

- Create the Promise outside render (in a useState initializer or an event handler) and keep it in state. Calling fetchPosts() in render creates a new Promise on every render, so the list suspends forever. Toggling the checkbox must not show the fallback again.

- <button className="reload">Reload</button> (outside the Suspense boundary) fetches the next version (2, 3, …). Wrap the state update in startTransition from useTransition: React then keeps the old posts on screen instead of the fallback. While the transition is pending, show <p className="refreshing">Refreshing…</p> and disable the button.

Next: Static or Dynamic? Route Classifier