fix(match): bind useContext for state vars used in rx.match case conditions#6676
fix(match): bind useContext for state vars used in rx.match case conditions#6676picklelo wants to merge 1 commit into
Conversation
Greptile SummaryFixes a
Confidence Score: 5/5Safe to merge — the change is narrowly scoped to surfacing previously-invisible Vars from Match's case conditions and has a regression test that directly covers the broken pattern. Both changes in No files require special attention. Important Files Changed
Reviews (2): Last reviewed commit: "fix(match): bind useContext for state va..." | Re-trigger Greptile |
Merging this PR will not alter performance
Comparing Footnotes
|
…itions rx.match only counted its subject toward statefulness, so a state Var used only in a case condition with a literal subject -- e.g. rx.match(True, (State.x > 0, comp), ...) -- left Match un-memoized. The compiled switch then referenced the substate context variable without a useContext binding, raising "ReferenceError: Can't find variable" at render (the page route emits useContext only via memoized children). Surface the case-condition Vars in Match._get_vars (and merge their var-data in add_imports, mirroring the Var-return branch) so Match is memoized when a case condition is stateful and the binding is emitted. Keeps the existing passthrough strategy (branches still memoize independently). Adds a regression test. Fixes #6675. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
c4055e4 to
6ea5a31
Compare
|
This does seem to work, but now that memoization mode is |
Problem
rx.match(...)with component branches and a state Var used in a case condition raises a frontendReferenceError: Can't find variable: reflex___state____state__...at render. The idiomatic "match on a literal subject" form triggers it:Reported in #6675 (with a compiled-output trace).
Root cause
Matchrendered itsswitchinline into the page component, and the per-case condition Vars live inmatch_cases(which is not a JS property), so they were never surfaced to the compiler. The page route emits stateuseContextbindings only through memoized child components, never inline — so the inlined switch referenced the substate context variable without ever binding it.The
Var-return branch of_create_match_cond_var_or_componentalready merges the case-condition var-data; the component-return branch did not, andMatchhad no_get_vars/ memoization handling for the conditions.Fix
_memoization_mode = MemoizationMode(recursive=False)— renderMatchinside a snapshot memo wrapper (mirrorsForeach, whose stateful render logic likewise belongs in the memo body), so the switch + conditions get an in-scopeuseContextbinding instead of being inlined into the page component._get_varsto also yield the per-case condition Vars, so their hooks (theuseContextbindings) are emitted.add_importsnow merges the case-condition var-data (mirrors theVar-return branch), so theStateContexts/useContextimports are present.Verification
Compiled a minimal repro (
rx.match(True, (S.a > 0, ...), (S.b > 0, ...), default)) with the patch:_index.jsx) no longer references the substate var (previously the unbound reference).Match_comp_*.jsxmemo wrapper is now generated that declaresconst ...state = useContext(StateContexts....)and contains theswitchreferencing the now-bound var.rx.cond)".ruff checkandruff format --checkpass.Fixes #6675.