Skip to content

Fix local client state across sibling components - #7442

Open
harsh21234i wants to merge 17 commits into
reflex-dev:mainfrom
harsh21234i:fix/7426-local-client-state-sibling
Open

harsh21234i wants to merge 17 commits into
reflex-dev:mainfrom
harsh21234i:fix/7426-local-client-state-sibling

Conversation

@harsh21234i

@harsh21234i harsh21234i commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #7426, where calling a local client-state setter from a sibling component could raise a ReferenceError and leave the displayed value unchanged.

The compiler now detects when local client state is shared across components and keeps those components in a compatible React scope. Added a compiler regression test and a Playwright test that verifies the sibling setter updates the rendered value. Included changelog entries for both affected packages.

Testing: Targeted unit and Playwright tests, Ruff, Pyright, and git diff --check pass locally.

Review in cubic

@harsh21234i
harsh21234i requested a review from a team as a code owner October 6, 2026 08:09

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 7 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread reflex/compiler/plugins/memoize.py Outdated
Comment thread news/+7426.bugfix.md Outdated
@greptile-apps

greptile-apps Bot commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 4/5

[Medium impact] The change affects page compilation for pages that use local client state.

The PR needs one more fix before merging: default styles can still split shared local state.

Findings

  1. P1 Default styles stop updating ▶

Summary

Keeps sibling components that share local client state in the same React scope.

  • Local client-state readers and setters stay in one React scope.

Reviews (16) · Last reviewed commit: "fix: preserve empty component style scop..." · Reviewed by Greptile

Comment thread reflex/compiler/plugins/memoize.py Outdated
@codspeed

codspeed Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Merging this PR will degrade performance by 5.5%

2 warnings

⚠️ 14 benchmarks are dominated by system calls

System calls cannot be simulated consistently and are left out of the measure. The reported value understates the real cost. Switch to the Walltime instrument to measure them.

Learn more about system calls

See affected benchmarks

⚠️ Base and head ran on different runner types

Some benchmarks with significant performance changes were compared across different runner types, so the changes might not come from the code. Run base and head on the same runner type, or use CodSpeed Macro Runners for more stable results.

Learn more about Macro Runners

Open the report in CodSpeed to investigate

❌ 8 regressed benchmarks
✅ 140 untouched benchmarks

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
❌ test_compile_all_artifacts[_complicated_page] 130.3 ms 142.2 ms -8.4%
❌ test_compile_all_artifacts[_stateful_page] 38 ms 40.3 ms -5.7%
❌ test_compile_page[_complicated_page] 194.1 ms 205.8 ms -5.69%
❌ test_compile_page_full_context[_complicated_page] 210.7 ms 222.6 ms -5.34%
❌ test_compile_page_full_context[_stateful_page] 45.9 ms 48.4 ms -5.08%
❌ test_compile_page[_stateful_page] 43.4 ms 45.6 ms -4.99%
❌ test_compile_all_artifacts[_repeated_stateful_page] 446.5 ms 468.1 ms -4.62%
❌ test_compile_page[_repeated_stateful_page] 519.2 ms 541.3 ms -4.1%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing harsh21234i:fix/7426-local-client-state-sibling (83062a4) with main (a9b6613)

Open in CodSpeed

@masenf masenf added the bug Something isn't working label Oct 6, 2026
Comment thread reflex/compiler/plugins/memoize.py Outdated
Comment thread reflex/compiler/plugins/memoize.py Outdated
Comment thread reflex/compiler/plugins/memoize.py Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 4 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Re-trigger cubic

Comment thread reflex/compiler/plugins/memoize.py Outdated
Comment thread reflex/compiler/plugins/memoize.py Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 1 file (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

View guided diff | Re-trigger cubic

Comment thread reflex/compiler/plugins/memoize.py Outdated
Comment thread reflex/compiler/plugins/memoize.py Outdated
@FarhanAliRaza FarhanAliRaza added the on deck PRs lined up to review / merge next label Oct 22, 2026
Comment thread tests/units/reflex_bench/suites/test_memory.py Outdated
Comment thread reflex/compiler/plugins/memoize.py Outdated
Comment thread reflex/compiler/plugins/memoize.py Outdated
Comment thread reflex/compiler/plugins/memoize.py Outdated
Comment thread reflex/compiler/plugins/memoize.py

@masenf masenf left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm not too keen on patching memo plugin so deeply to support the old experimental client_state.

the new client state already uses scoped access on the javascript side and just works transparently without all this compiler machinery.

@masenf masenf removed the on deck PRs lined up to review / merge next label Oct 22, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 4 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Re-trigger cubic

Comment thread reflex/compiler/plugins/memoize.py Outdated
@harsh21234i

Copy link
Copy Markdown
Contributor Author

Thanks, I understand the concern. I’ve simplified the prepass based on the review feedback, but this still adds compiler logic for the legacy experimental API. Since the newer client-state API already handles scoped access, would you prefer we keep a compatibility fix for this existing behavior, or close/defer this issue and direct users to the newer API?

Comment on lines +171 to +175
for data in var_data:
local_scope_keys.update(data.shared_scope_keys)
local_scope_keys.update(
_component_style_scope_keys(component, style_scope_keys)
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Default styles stop updating

Local state added by add_style() is missing from this scan. For example, subclass AutoScroll, return {"color": local.value} from add_style(), and place it beside a local.value reader and setter. The root scan runs before the child's default style is applied and only accounts for App.style. The child can then get its own memo component and state, so clicking the outside setter leaves its color unchanged.

Include default-style state users before computing the shared-scope decisions.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Local rx._x.client_state setter raises ReferenceError when the setter is on a sibling component

3 participants