React Forum
Blog & Guide Responses
Jan 22, 2023 · 04:00 AM

Sharing state between components - discussion (2023-01-22)

Started by Jules Kwon
externalreact.devshared statelifting stateroute contractsstored derived stateevidence

This page is the default answer to "where should this state live", but in practice the decision is rarely just "lift it". In route-first apps, a lot of shared state is really a contract decision (route keys vs documents vs vaults) and the big goal is coherence and debuggability, not just fewer props.

Read the article

When do you lift state vs define a shared contract (route shell, document, or vault)? When do you store derived shared keys (visible ids, counts) instead of recomputing in each consumer? What evidence do you render so shared state changes are explainable in screenshots?

Comments (14)

Back to latest
Marisol Vega
Jan 26, 2023 · 12:12 PM

If the shared thing is 'motion' (panel, selection, overlay), we keep it in route state so back/forward is predictable.

If it's domain data, we keep it in a vault or document.

Dmitri Kline
Feb 06, 2023 · 06:22 AM

Storing derived shared keys is the underrated option. If three siblings need the same filtered ids, store them once and render them as evidence.

ts
function deriveVisible(doc: any) {
  const items = doc.read('items');
  const q = doc.read('q').trim().toLowerCase();
  const visibleIds = q ? items.filter((x: any) => x.title.toLowerCase().includes(q)).map((x: any) => x.id) : items.map((x: any) => x.id);
  doc.write('visibleIds', visibleIds);
  doc.write('resultCount', visibleIds.length);
}

Then selection self-correction becomes straightforward.

Keira Santos
Feb 18, 2023 · 06:18 PM

Counterpoint: storing derived keys is only safe if mutations are disciplined.

If anyone can update items without re-deriving, the UI becomes inconsistent.

Jules Kwon
Feb 21, 2023 · 07:44 AM

Agree. The pattern needs a single mutation path or a reconcile step that always runs.

Otherwise you're encoding invariants in people's heads.

Grace McCoy
Mar 07, 2023 · 04:04 AM

We lift state when the nearest ancestor is already a meaningful boundary (shell/document root).

If we lift to a random wrapper, it becomes a ghost boundary nobody understands.

Jasper Nguyen
Mar 25, 2023 · 09:10 PM

Evidence key that helped us a lot: store and render lastIntent.

If selection changes or a filter resets something, you can explain why.

Nina Kapoor
Apr 14, 2023 · 12:02 PM

We prefer prop threading inside a single route shell.

Once you start using context/global stores just to avoid props, you've traded clarity for convenience.

Camille Duarte
May 02, 2023 · 09:12 AM

A misunderstanding I see: people think shared state is scary because it's global.

It's scary because it's invisible. Render the shared keys as evidence and it gets much calmer.

Owen Price
May 21, 2023 · 06:06 AM

We draw the line at ownership: who owns the write path?

If no one owns it, shared state rots quickly.

Benji Rios
Jun 12, 2023 · 06:30 PM

Docs tie-in: sharing state is mostly about contracts and evidence.

Related: State Management (Best Practices) and Components and Composition.

Lina Ortega
Jul 07, 2023 · 03:03 AM

Counterpoint: you can over-design shared state.

If the state is ephemeral (hover, focus), keep it local and don't turn it into a contract.

Marisol Vega
Jul 10, 2023 · 02:22 PM

Agree. The contract story is for state that users care about and expect to be stable.

Local ephemeral state is fine as long as it doesn't leak into app behavior.

Amina Farouk
Aug 02, 2023 · 08:55 AM

We stopped calling it 'lifting state' and started calling it 'choosing an owner'.

Once ownership is explicit, the rest of the decision gets easier.

Tomas Rivera
Aug 26, 2023 · 08:01 PM

We also store derived resultCount alongside visibleIds because counts are UI evidence, not just math.

If the header and list disagree, users report it as a bug immediately.

Sofia Valdez
Sep 16, 2023 · 10:10 AM

We render data-selected and data-visible-count on the shell behind a flag.

It's ugly, but it made support work possible.

Evan Brooks
Oct 20, 2023 · 04:04 AM

If shared state feels hard, it's probably because the app doesn't have a stable contract for it yet.