Skip to content

Latest commit

 

History

History
67 lines (59 loc) · 1.8 KB

light-months-argue.md

File metadata and controls

67 lines (59 loc) · 1.8 KB
react-router @remix-run/router
patch
patch

Feat: adds defer() support to data routers

Returning a defer() from a loader allows you to separate critical loader data that you want to wait for prior to rendering the destination page from non-critical data that you are OK to show a spinner for until it loads.

// In your route loader, return a defer() and choose per-key whether to
// await the promise or not.  As soon as the awaited promises resolve, the
// page will be rendered.
function loader() {
  return defer({
    critical: await getCriticalData(),
    lazy: getLazyData(),
  });
};

// In your route element, grab the values from useLoaderData and render them
// with <Await> inside a <React.Suspense> boundary
function Page() {
  let data = useLoaderData();
  return (
    <>
      <p>Critical Data: {data.critical}</p>
      <React.Suspense fallback={<p>Loading...</p>}>
        <Await resolve={data.lazy} errorElement={<RenderError />}>
          <RenderData />
        </Await>
      </React.Suspense>
    </>
  );
}

// Use separate components to render the data once it resolves, and access it
// via the useAsyncValue hook
function RenderData() {
  let data = useAsyncValue();
  return <p>Lazy: {data}</p>;
}

function RenderError() {
  let data = useAsyncError();
  return <p>Error! {data.message} {data.stack}</p>;
}

If you want to skip the separate components, you can use the Render Props pattern and handle the rendering of the deferred data inline:

function Page() {
  let data = useLoaderData();
  return (
    <>
      <p>Critical Data: {data.critical}</p>
      <React.Suspense fallback={<p>Loading...</p>}>
        <Await resolve={data.lazy} errorElement={<RenderError />}>
          {(data) => <p>{data}</p>}
        </Await>
      </React.Suspense>
    </>
  );
}