Used to render promise values with automatic error handling.
Passing the promise through resolve uses React Router-specific promise tracking, while passing
it through unstable_promise uses React's built-in use()
API.
Note: <Await> expects to be rendered inside a <React.Suspense>
unstable_promise prop is currently unstable and may change in minor or patch
releases. We plan to stabilize <Await promise> and deprecate <Await resolve> during v8, and then
drop <Await resolve> in v9. Please see below for minor errorElement behavioral differences
between the two approaches.
import { Await, useLoaderData } from "react-router";
export async function loader() {
// not awaited
const reviews = getReviews();
// awaited (blocks the transition)
const book = await fetch("/api/book").then((res) => res.json());
return { book, reviews };
}
function Book() {
const { book, reviews } = useLoaderData();
return (
<div>
<h1>{book.title}</h1>
<p>{book.description}</p>
<React.Suspense fallback={<ReviewsSkeleton />}>
<Await resolve={reviews} errorElement={<BookError />}>
{(resolvedReviews) => <Reviews items={resolvedReviews} />}
</Await>
</React.Suspense>
</div>
);
}
function Await<Resolve>(
props: AwaitProps<Resolve> | AwaitPromiseProps<Resolve>,
)
When using a function, the resolved value is provided as the parameter.
<Await resolve={reviewsPromise}>
{(resolvedReviews) => <Reviews items={resolvedReviews} />}
</Await>
When using React elements, useAsyncValue will provide the
resolved value:
<Await resolve={reviewsPromise}>
<Reviews />
</Await>
function Reviews() {
const resolvedReviews = useAsyncValue();
return <div>...</div>;
}
The error element renders instead of the children when the
Promise
rejects.
When using resolve, errors thrown while rendering children are
also caught and rendered here. With unstable_promise, only promise
rejections are handled; errors thrown while rendering children bubble to
the nearest React error boundary.
<Await resolve={reviewsPromise} errorElement={<div>Oops</div>}>
<Reviews />
</Await>
To provide a more contextual error, you can use the useAsyncError in a
child component
<Await resolve={reviewsPromise} errorElement={<ReviewsError />}>
<Reviews />
</Await>
function ReviewsError() {
const error = useAsyncError();
return <div>Error loading reviews: {error.message}</div>;
}
If you do not provide an errorElement, the rejected value will bubble up
to the nearest route-level ErrorBoundary
and be accessible via the useRouteError hook.
Takes a Promise
returned from a loader to be
resolved and rendered.
import { Await, useLoaderData } from "react-router";
export async function loader() {
let reviews = getReviews(); // not awaited
let book = await getBook();
return {
book,
reviews, // this is a promise
};
}
export default function Book() {
const {
book,
reviews, // this is the same promise
} = useLoaderData();
return (
<div>
<h1>{book.title}</h1>
<p>{book.description}</p>
<React.Suspense fallback={<ReviewsSkeleton />}>
<Await
// and is the promise we pass to Await
resolve={reviews}
>
<Reviews />
</Await>
</React.Suspense>
</div>
);
}
A promise (or value) to read using React's use() API in client components.
Unlike resolve in client components, this accepts promise-like values
without modifying the source promise.
errorElement handles promise rejections. Errors thrown while rendering
children bubble to the nearest React error boundary.
<Await unstable_promise={reviewsPromise} errorElement={<ReviewsError />}>
{(reviews) => <Reviews items={reviews} />}
</Await>
Pass exactly one of unstable_promise or resolve.