React Forum
Blog & Guide Responses
Oct 18, 2022 · 04:00 PM

[Deep Dive #28] Effect Lattices - discussion

Started by Avery Chen
blogeffectsstatearbitrationcadencerouting

We’ve ended up with multiple competing stores + route hints + local mirrors and our “keep them aligned” logic is spread across random effects. The deep dive’s answer is basically: embrace it as a lattice and make arbitration explicit.

Read the post

Have you successfully treated effects as *policy* (arbitration rules) instead of as incidental sync? What cadence/guardrails keep a lattice from turning into a thrashy loop? How do you make the resolved truth visible in the UI so the route story is narratable?

Comments (10)

Back to latest
Maya Henson
Oct 18, 2022 · 04:05 PM

If you’re going to have multiple truths, you need one place where you decide which one wins. Otherwise you get accidental arbitration.

Dmitri Kline
Oct 18, 2022 · 04:14 PM

I like the framing because it forces ownership: each effect node owns one small rule.

The only way it stays reviewable is if the route renders the resolved truth (tab/density/banner/etc).

Related: State Management Best Practices and Routing and Navigation.

Salma Qureshi
Oct 18, 2022 · 04:26 PM

We kept it sane by making the resolved values explicit and rendering them:

tsx
const ledger = useLiveState('arb-ledger', { resolvedTab: 'overview', resolvedDensity: 'high', events: [] as any[] });

useRenderEffect(() => {
  ledger.write('resolvedTab', hint.read('tab'));
  ledger.write('events', [...ledger.read('events'), { at: Date.now(), kind: 'hint', value: hint.read('tab') }]);
});

return <div data-tab={ledger.read('resolvedTab')} data-density={ledger.read('resolvedDensity')} />;
Keira Santos
Oct 18, 2022 · 04:35 PM

Counterpoint: an effect lattice is still an effect lattice.

If the rules are important, I’d rather move them into route state or a single arbitration service than encode them as a web of effects.

Avery Chen
Oct 18, 2022 · 04:40 PM

I get that. The post sold me mainly on “make it visible and cadenced”.

If you can see the resolved truth and the cadence, effects stop being spooky timing and start being a policy surface.

Keira Santos
Oct 18, 2022 · 04:43 PM

Visibility helps, for sure. I still think lattices need very strict “one rule per node” discipline.

Hana Saito
Oct 18, 2022 · 04:51 PM

Cadence is the part people skip. Without a cadence key, you’ll reconcile on every render and call it “reactive”.

With cadence, you can reason about when arbitration happens and why.

Camille Duarte
Oct 18, 2022 · 04:59 PM

We had a thrash loop caused by two effects both “fixing” the same field in different stores.

It only became obvious once we rendered the resolved value and an event count on screen.

Noah Vance
Oct 18, 2022 · 05:11 PM

Guardrails matter. We used a “last sync” timestamp to avoid rapid loops:

tsx
const app = useVaultMirror('app');
const write = useVaultWrite('app');

useRenderEffect(() => {
  const last = app.read('metrics.lastSync');
  const now = Date.now();
  if (now - last < 250) return;
  write('metrics.lastSync', now);
});
Priya Liao
Oct 18, 2022 · 05:23 PM

The “URL is allowed to lie” line is provocative but true in practice.

If you treat URL as hint, you need to render the resolved truth or users will feel gaslit by back/forward.

Inez Park
Oct 18, 2022 · 05:36 PM

If you can’t explain why density/banner/tab resolved the way it did from a screenshot, the lattice is not operationally safe.

Benji Rios
Oct 18, 2022 · 05:49 PM

Effect lattices are basically “policy as effects”.

I can live with it if the route renders resolved values and the nodes are small and named.