Await Component

Use Suspense without creating a new component.

Demo

Suspense boundaries let you render fallback UI for parts of your page that depend on slow data requests, but they require you to create new component boundaries for those requests.

The <Await> component lets you avoid this friction. It takes in a promise, suspends until that promise fulfills, and then yields the result as a render prop. This lets you render fallback UI for slow data requests without having to create new components yourself.

Clicking a stock in the demo above instantly renders the main content, and uses <Await> to show a fallback spinner for the related stories.

Usage

// src/app/stocks/[stockId]/page.tsx
import { Await } from "@/components/await";

export default async function Stock({
  params,
}: {
  params: { stockId: string };
}) {
  // Page blocks on this data:
  const stock = await getStock(params.stockId);

  return (
    <div>
      <h1>{stock.name}</h1>

      <Suspense fallback={<Spinner />}>
        {/* ...but renders a spinner for this slower data: */}
        <Await promise={getRecentNews(stock)}>
          {(stories) => (
            <ul>
              {stories.map((story) => (
                <li key={story.id}>{story.title}</li>
              ))}
            </ul>
          )}
        </Await>
      </Suspense>
    </div>
  );
}

Code

Here's the code for the <Await> component.

// src/components/await.tsx
export async function Await<T>({
  promise,
  children,
}: {
  promise: Promise<T>;
  children: (result: T) => JSX.Element;
}) {
  let result = await promise;

  return children(result);
}

Libraries used

Get our latest in your inbox.

Join our newsletter to hear about Sam and Ryan's newest blog posts, code recipes, and videos.