Skip to content

docs(rfc): amend context-selector-tearing with Option D (Relay pattern)#36001

Draft
layershifter wants to merge 4 commits intomasterfrom
layershifter/rfc-context-selector-option-d
Draft

docs(rfc): amend context-selector-tearing with Option D (Relay pattern)#36001
layershifter wants to merge 4 commits intomasterfrom
layershifter/rfc-context-selector-option-d

Conversation

@layershifter
Copy link
Copy Markdown
Member

docs: amend context-selector-tearing RFC with Option D (Relay pattern)

Summary

Amends docs/react-v9/contributing/rfcs/react-components/context-selector-tearing.md with a new "Addendum" section documenting Option D: a hook rewrite modeled on Relay's useFragmentInternal.

The original RFC considered Options A, B, C and selected A ("do nothing"). Option D was not considered at the time — it emerged from a conversation with the React team after the decision was made. Option D strictly improves on Option A for the "Glitchy Behavior" case without regressing anything else.

Why amend rather than replace

The original decision record is load-bearing context: it documents the reasoning for rejecting Options B and C, the test harness, and the "Level 1 tearing is acceptable" framing. Keeping it intact and appending an addendum preserves that history. The addendum section is clearly dated and labeled as revisiting the decision in light of new evidence and a new option.

What's in the addendum

  1. New root-cause analysis of the "Glitchy Behavior" note the original RFC flagged but didn't bottom out. The bug is a fiber.lanes pollution issue in React's dispatchSetStateInternal eager-bailout check — the bound-at-mount fiber becomes the stale alternate after the first listener-driven commit and its lanes never get cleared, permanently failing the NoLanes precondition.
  2. Empirical confirmation via patched react-dom.development.js that logs fiber.lanes / alternate.lanes at the check site. First dispatch: fiber=0 alt=0 eager=TRUE. All subsequent dispatches on that fiber: fiber=1 alt=0 eager=FALSE.
  3. Option D specification: read valueRef.current during render (like useSyncExternalStore.getSnapshot), no [value, selected] state tuple, no setState(prev => prev) bailout trick. Listener compares selector(newValue) against a layout-effect-latched lastReturnedRef.current and force-updates only when the slice actually differs. Matches Relay's useFragmentInternal_CURRENT.js pattern.
  4. Comparison table vs Option A: fixes the glitch, preserves everything else (tearing behavior, concurrent safety, public API).
  5. Why not B or C (unchanged): B still doesn't fix the glitch per the original RFC's test, C has a newly-empirically-verified concurrent-mode hazard where uncommitted transition values leak into sibling urgent renders.
  6. Measurements from the investigation repo's probe suite.

Accompanying PR

microsoft/fluentui#<TBD> — implementation of Option D in @fluentui/react-context-selector. The two PRs can merge in either order; the doc PR stands on its own as the architectural record.

Test plan

  • Prose-review the addendum section (peer reviewer).
  • Verify the diff against main is additive — no existing sections modified.

Out of scope

  • Level 1 tearing. Unchanged from original RFC.
  • Any API changes. Option D is API-compatible.

The original RFC considered Options A, B, C and selected A (do nothing).
Option D was not considered at the time — it emerged from a conversation
with the React team after the decision was made.

This addendum:
- Documents the root cause of the original RFC's "Glitchy Behavior" note:
  fiber.lanes pollution on the bound-at-mount fiber in
  dispatchSetStateInternal's eager-bailout check.
- Specifies Option D: allow Level 1 tearing, heal in effect via
  epoch/selector check. Matches Relay's useFragmentInternal pattern.
- Compares Option D to Option A across glitch, tearing, concurrent
  correctness, lint, and API dimensions.
- Re-establishes why Options B and C remain inadequate, with new empirical
  evidence against C (uncommitted-transition value leaks to urgent sibling
  renders under concurrent mode).
- Includes measurements from an investigation probe.

Does not modify the original decision record. The addendum is clearly dated
and labeled so the history of the prior decision is preserved.

Accompanying implementation PR: layershifter/fix-context-selector-bailout.
@github-actions github-actions bot added the Type: RFC Request for Feedback label Apr 18, 2026
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 18, 2026

📊 Bundle size report

✅ No changes found

@github-actions
Copy link
Copy Markdown

Pull request demo site: URL

…nk public repro

- Drop references to docs/phase-3-root-cause.md, docs/phase-5-comparison.md,
  and repro/tests/list-probe-cycling.json (private investigation workspace).
- Replace with link to public reproduction repo:
  https://github.com/layershifter/context-selector-bailout-repro
- Pin Relay implementation references to commit e3c9d1b5661fb6f58e4d58f81cd930e09a47a89a
  so links don't move as main progresses.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Type: RFC Request for Feedback

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant