I have critical data and noncritical data. Both are provided through the loader. I want to transmit the noncritical data as a promise using defer.

Given the following example, I would expect "quickAndCritical" to be rendered after about 1s and "slow" about 2s later. But actually the page stays blank for about 3s and then renders both.

Am I making a mistake here? I would appreciate any help!

import React, { Suspense } from "react";
import { defer } from "@remix-run/node";
import { Await, Links, Meta, useLoaderData } from "@remix-run/react";
import type { LoaderFunction, LoaderFunctionArgs } from "@remix-run/node";

export function quickAndCritical() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve("quickAndCritical");
    }, 1000);
  });
}

export function slowAndDeferrable() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve("slow");
    }, 3000);
  });
}

export const loader: LoaderFunction = async ({ request }: LoaderFunctionArgs) => {
  const critical = await quickAndCritical();
  const canBeDeferred = slowAndDeferrable();

  return defer({
    critical,
    canBeDeferred,
  });
};

export default function App() {
  const { critical, canBeDeferred } = useLoaderData();

  return (
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width,initial-scale=1" />
        <Meta />
        <Links />
      </head>
      <body>
        {critical}
        <br></br>
        <br></br>
        <Suspense fallback={null}>
          <Await resolve={canBeDeferred}>{(resolvedData) => <div>{resolvedData}</div>}</Await>
        </Suspense>
      </body>
    </html>
  );
}

2

There are 2 answers

1
Justin Wallace On

According to the Remix Docs, you need to initiate promises for deferred data before you await any other promises.

Swapping lines 1 & 2 should do the trick for ya.

export const loader: LoaderFunction = async ({ request }: LoaderFunctionArgs) => {
  const canBeDeferred = slowAndDeferrable();
  const critical = await quickAndCritical();
  

  return defer({
    critical,
    canBeDeferred,
  });
};
0
Max On

In case you are using the Shopify CLI to preview your app, this might be caused by the Cloudflare proxy which apparently does not support streaming.

See here for more detail and a workaround.