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.