Skip to content

Refactor ClientStateVar: scoped client state via a useClientState hook (rx.client_state) #7610

Description

@masenf

Problem

rx._x.client_state (ClientStateVar) is experimental and implemented as a per-component useState plus a shared mirror in refs, fanned out through the app root. Known limitations:

Proposal

Reimplement client state on a useClientState hook backed by a per-var slot store, and promote the API to rx.client_state(default, name=...).

  • Scoping. Named vars are global and addressable from the backend; unnamed vars are scoped to the component tree that first uses them, so each @rx.memo instance and each rx.foreach item gets its own value, the way React's useState does. A ClientStateProvider app wrap mounts the store; ClientStateScope marks scope boundaries (one per rendered loop item).
  • Per-slot subscriptions. Each var has its own listener set, so writing one var only re-renders its subscribers.
  • Backend integration. Global vars can be pushed from and retrieved by event handlers over new wire events (_client_state_set, _client_state_get).
  • Functional updaters. .set accepts a value, a FunctionVar, or a Python lambda traced at compile time (count.set(lambda v: v + 1)) and replaces .set_value.
  • SSR isolation. A fresh store per server-rendered request.
  • Compiler. Client-state setters are auto-memoized; hooks, imports and app wraps are collected through VarData. Each rendered foreach item publishes its value and index to its subtree, so a consumer reads them wherever the compiler places it (fixes [REF-2745] rx.form handle_submit lambda cannot reference foreach vars #3210). Foreach is no longer a snapshot boundary for auto-memoization, so a loop-var consumer becomes its own memo component.
  • Compat. rx._x.client_state.ClientStateVar keeps working with a deprecation warning; rx.client_state is the stable path.
  • Coverage. Vitest tests for the store, subscriptions, SSR isolation, provider lifecycle and scopes (Unit-test the shipped frontend JavaScript with standard JS tooling (vitest) #7611); Python unit tests for hook/import/app-wrap emission and setters; Playwright tests for runtime behavior, backend push/retrieve, and per-item loop state.

Pending work

The implementation is #6936 (draft, 48 files, +6664/-533). Outstanding before it can be marked ready:

Related

Activity

  1. added theissue type on Oct 20, 2026
  2. linear-code commented on Oct 20, 2026

    @linear-code
  3. added
    roadmaphttps://github.com/reflex-dev/reflex/issues/2727
    on Oct 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    roadmaphttps://github.com/reflex-dev/reflex/issues/2727

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions