BlogCache Components

Last update

  1. Create a single promise in the parent with db.getProduct(id) (without await)
  2. Pass that promise to each field component
  3. Wrap each field in its own <Suspense>
  4. Deconstruct inside each component: const { stock } = await productPromise

Demo Route

  • /product/[id]/shared-promise
  • Direct example: /product/1/shared-promise

Implementation

app/product/[id]/shared-promise/_components/product-content-shared-promise.tsx
export async function ProductContentSharedPromise({ params }) {
  const { id } = await params;
  const safeProductId = parseProductId(id);

  // A single call / a single promise
  const productPromise = db.getProduct(safeProductId);

  return (
    <>
      <Suspense fallback={<ProductTextFromPromiseSkeleton />}>
        <ProductTextFromPromise productPromise={productPromise} />
      </Suspense>

      <Suspense fallback={<ProductPriceFromPromiseSkeleton />}>
        <ProductPriceFromPromise productPromise={productPromise} />
      </Suspense>

      <Suspense fallback={<ProductStockFromPromiseSkeleton />}>
        <ProductStockFromPromise productPromise={productPromise} />
      </Suspense>
    </>
  );
}

Each block consumes the same promise:

Block Example
export async function ProductStockFromPromise({ productPromise }) {
  const { stock, lastChecked } = await productPromise;
  return (
    <div>
      {stock} - {lastChecked}
    </div>
  );
}

What You Gain and What You Lose

  • ✅ A single query per request for the complete payload
  • ✅ Less duplication of data access logic
  • ✅ Visual granularity: each block maintains its own Suspense
  • ✅ Useful when fields change together or the record is small

There is no universally better option. This pattern prioritizes data access simplicity + a single query, while the multi-query approach prioritizes field-level invalidation.

When to Use Each Pattern

  • Shared promise (getProduct): When you want a single query and data that usually travels together.
  • Granular multi-query: When text/price/stock have different lifecycles and you need tags per field.

How to Validate It in the Demo

  1. Open /product/1/shared-promise
  2. Look at the server console
  3. You should see getProduct (all fields) once per request on that route
  4. Compare with /product/1, where you will see separate queries per field

On this page