Used
How toHandle deferred data in React Router
If you're using React Router v7 you may not know you can return pending promises from loaders instead of awaiting them in your loader. This allows you to handle loading states directly in your components, useful for slow data fetching scenarios, or in case you want the user to navigate instantly to the page while the data is still loading.
React Router's Await
If you came from Remix v2, this was done using defer
response helper and useDeferredValue
hook or Await
component, paired all with React's Suspense.
In React Router v7 you can achieve the same without using defer
, simply by returning a promise from your loader function. Here's how you can do it:
import { Suspense } from "react"; import { Await } from "react-router"; export function loader() { // This can also be an object with a promise property, or even an array of // promises. return new Promise((resolve) => { setTimeout(() => { resolve("Hello, world!"); }, 1000); }); } export default function Component({ loaderData }: Route.ComponentProps) { return ( <div> <h1>My Component</h1> <Suspense fallback={<p>Loading...</p>}> <Await resolve={loaderData}>{(data) => <p>{data}</p>}</Await> </Suspense> </div> ); }
React.use
If you're using React 19 you can also use React.use
:
import { Suspense, use } from "react"; export default function Component({ loaderData }: Route.ComponentProps) { return ( <div> <h1>My Component</h1> <Suspense fallback={<p>Loading...</p>}> <Result promise={loaderData} /> </Suspense> </div> ); } function Result({ promise }: { promise: Promise<string> }) { const data = use(promise); return <p>{data}</p>; }
As you can see, using React.use
requires more boilerplate than using Await
since you need a new component where you call use
with the promise.
Promise as a Renderable Node
However, a less known feature in React 19 is that you can directly use a promise as a rendereable node, this allows you to use the promise directly in your component without needing an additional wrapper:
import { Suspense } from "react"; export default function Component({ loaderData }: Route.ComponentProps) { return ( <div> <h1>My Component</h1> <Suspense fallback={<p>Loading...</p>}> {loaderData.then((data) => ( <p>{data}</p> ))} </Suspense> </div> ); }
See how much simpler this becomes, you can use the promise without needing React Router's Await
and without creating an extra component for React.use
.