How toDefer a Fetch response in Remix

The defer response helper in Remix let stream part of the response from a loader so we don't block the response to the browser when doing something slow.

If you're doing a fetch to a slow API that you don't control you may want to use defer to stream the response.

A first approach may be doing something like this:

app/routes/something.tsx
export async function loader() { return defer({ data: fetch("https://api.third-party.com") }) }

The problem with this is that while it will defer the fetch itself, the result of fetch is a Response object, not the actual data, we have to do response.json() to parse the response body and access the data, and we have to do this in our loader.

app/routes/something.tsx
export async function loader() { return defer({ data: fetch("https://api.third-party.com").then(res => res.json()) }) }

Now the promise that defer will stream will be the result of doing the fetch and parsing the response body.

Finally, we can use Await and Suspense to render our UI.

app/routes/something.tsx
export default function Component() { let { data } = useLoaderData<typeof loader>(); return ( <Suspense fallback={<Spinner />}> <Await resolve={data}> {(data) => <RenderData data={data} />} </Await> </Suspense> ); }

And it should work.