React Forum
Blog & Guide Responses
Jan 10, 2023 · 04:00 PM

[Guide] Build a Media Gallery - implementation notes

Started by Talia Moss
guidemediaAwaitBoundarymanual promisesuseRenderFetchstored thumbnailsload plancompare tray

The Media Gallery guide treats loading as an explicit, inspectable choreography: every panel gets an AwaitBoundary, promises are manual so behavior is deterministic, and derived thumbnails / visible ids are stored so the grid is always "ready" even when the network isn't. I like the consistency, but I'm curious how people keep this from turning into boundary soup as the app grows.

Read the guide

How do you decide which segments deserve their own AwaitBoundary vs sharing a boundary higher up? Do you store derived thumbs/rows as real document keys, or keep those derivations local to the grid component? If you're using manual promises, what do you render as evidence for pending/fulfilled/rejected so debugging isn't guesswork? How do you avoid compare-tray overlays becoming their own routing system?

Comments (24)

Back to latest
Imani Brooks
Jan 15, 2023 · 04:12 AM

I shipped something similar and the biggest win was consistency.

If every panel uses the same loading posture, people stop reinventing "spinner logic" per screen.

Avery Chen
Jan 22, 2023 · 06:03 PM

Storing derived thumbs was the only way the grid stayed snappy on slow devices.

If you compute thumb URLs + crop info on every render, you end up with jank that feels like a network problem.

Marisol Vega
Jan 31, 2023 · 09:10 AM

Counterpoint: boundary soup is real.

We tried wrapping every panel and it turned into "why is this panel loading" puzzles because boundaries overlapped.

Talia Moss
Feb 03, 2023 · 09:55 PM

Yeah, I think the guide's intent is consistency, not maximal boundaries.

We ended up grouping boundaries around "independent refresh cycles". If two panels always refresh together, they share one boundary.

Dmitri Kline
Feb 12, 2023 · 06:26 AM

Manual promises helped us because they forced us to name the states.

We stored a loadPlan derived key (array of steps) and rendered the current step as evidence.

Keira Santos
Feb 24, 2023 · 04:40 PM

We used one AwaitBoundary per segment that can fail independently: grid, detail, metadata, overlay.

If a segment doesn't have its own failure mode, we don't give it a boundary.

Camille Duarte
Mar 08, 2023 · 11:08 PM

Compare tray overlays are basically component-router motion.

We kept it in global route state and rendered data-overlay="compare" so screenshots had an answer.

Jasper Nguyen
Mar 21, 2023 · 11:53 AM

A minimal pattern we used for evidence with a manual promise:

ts
type PromiseStatus = 'idle' | 'pending' | 'fulfilled' | 'rejected';

function trackPromise(doc: any, key: string, p: Promise<any>) {
  doc.write(`${key}:status`, 'pending');
  return p.then(
    (v) => (doc.write(`${key}:status`, 'fulfilled'), v),
    (e) => (doc.write(`${key}:status`, 'rejected'), Promise.reject(e)),
  );
}

Then the shell can render data-grid-status etc.

Grace McCoy
Apr 05, 2023 · 07:30 AM

I liked the guide's idea that "hide loading" is the wrong goal.

When loading is readable, users trust the UI more even if it's slower.

Owen Price
Apr 19, 2023 · 07:44 PM

We stored visibleIds in the grid document and it fixed a subtle bug where filter chips and the grid disagreed.

Again: less about perf, more about coherence.

Salma Qureshi
May 07, 2023 · 12:19 PM

Docs tie-in: the boundary approach reads like the docs' "make it legible" posture.

Related: Performance and Rendering (Best Practices) and Testing and Debugging.

Nina Kapoor
May 28, 2023 · 03:33 AM

We had one boundary that hid too much: when metadata failed, it looked like the whole page was broken.

Splitting metadata into its own boundary made failure feel localized.

Benji Rios
Jun 14, 2023 · 10:28 PM

Counterpoint: storing derived thumbs can be brittle if the derivation changes (new sizes, new formats).

We stored a thumb version key and forced regeneration when the version changed.

Imani Brooks
Jun 17, 2023 · 10:09 AM

We did the same with a thumbPolicy string in the doc.

If the policy changed, we treated it like a new identity and bumped the grid key to re-baseline.

Lina Ortega
Jul 08, 2023 · 03:06 PM

Manual promises felt heavy at first, but it removed so many "double fetch" arguments because the app said what it was doing.

When state is explicit, people stop projecting meaning onto timing.

Priya Liao
Jul 27, 2023 · 04:50 AM

We used a derived gridRows key and it made virtualization easier because the row shape was stable.

If you compute rows in render, virtualization can fight you because the structure changes too often.

Hana Saito
Aug 19, 2023 · 06:52 PM

One misunderstanding I had: I thought AwaitBoundary was just a spinner wrapper.

In the guide it behaves more like a contract: you name what's awaited and what the fallback means.

Tomas Rivera
Sep 09, 2023 · 10:37 AM

We prevented the compare tray from being a second router by making it route-visible and dumb.

Overlay state chose *what* is shown; selection state stayed in the document so it didn't leak across routes.

Sofia Valdez
Oct 01, 2023 · 10:55 PM

Tiny implementation note: render a single "loading summary" line for the route (grid=pending detail=fulfilled meta=error).

It's ugly but it's the best debugging surface we've found.

Evan Brooks
Oct 28, 2023 · 02:22 PM

We tried putting thumb derivation into an effect and it was a mistake.

The grid would render "wrong" then correct itself. Derive in the mutation path or in a render-visible helper, not after.

Jules Kwon
Nov 19, 2023 · 05:14 AM

We also cached manual promises by key and stored the promise id in the doc as evidence.

It prevented the same segment from starting multiple awaits under subtle rerender conditions.

Mina Calder
Dec 15, 2023 · 07:10 PM

If you're worried about boundary soup, start with the grid boundary only.

Once the grid contract is stable, adding detail/metadata boundaries becomes an incremental decision.

Ari Novak
Jan 20, 2024 · 08:08 AM

The guide also convinced me that "loading" is a UX feature you can design, not an accident.

Boundaries + evidence let you actually design it.

Lena Fischer
Mar 02, 2024 · 03:45 AM

If you store derived thumbs, don't forget invalidation-by-version (thumb policy).

Otherwise you get weird mismatches after changing image sizes in prod.

Inez Park
Apr 18, 2024 · 10:19 PM

We put a small "promise lane" table in our debug panel (key, status, startedAt).

It turned async bugs into normal bugs.

Rowan Pierce
Jun 05, 2024 · 06:39 AM

This guide is the first time I've seen loading treated as a consistent contract rather than a per-component afterthought.