Feature Request: Shared/Scoped State
As already proposed on discord, we see many good point to have something like shared state or state that is bound to a specific identifier. The use cases reach from user scope for authentication/settings over chat groups or collaborative list views to news feeds and on-the-fly application settings.
Just to illustrate the idea
class AppState(rx.State):
@rx.var
def user_id(self) -> UUID:
...
...
@rx.scope(var=AppState.user_id)
class UserState(AppState):
mySettings: ...
@rx.scope(var=AppState.group_id)
class ListState(AppState):
@rx.cached_var
def elements(self):
with rx.session() as session:
return load_objects_with_group_id(session, AppState.group_id)
# Maybe inheritance from AppState is not needed anymore #2678
From my current understanding of the framework I see e.g. this implementation strategy:
- Add a
scoped_tokenproperty to Event, that calculates from the scope-var (i.e.AppState.user_idorAppState.group_idin above examples). - When also the
StateManagerMemoryimplements the same sharding mechanism asStateManagerRedisno further changes have to be made here. - In
App.processthe resulting events have to be sent tosocket.io-rooms. - Socket room management has to be done on changes to the scope-var.
- On connect and disconnect have to restore the subscriptions to the rooms.
- For the case of multiple running app instances redis pubsub has to be implemented, where the
scoped-tokenvalue can be used as topic name. On events in the subscribed topics those can be sent to the targeted rooms. - Events coming from the frontend need to have the
scoped-tokenset by their respective frontend handlers.
When thinking about it, maybe the current state handling is only a special case, so no @rx.scope means the socket/tab scope. Maybe that is a better way to view this architecturally.
There might be many implications that I haven't thought through in detail, yet. E.g. what about @rx.background in those scoped states.
This could also be described as "Dynamic State". Currently, it is not possible to reuse a State multiple times at runtime (f.e. ComponentState in a rx.foreach). All state names/classes must be known at compile time.
Maybe we should implement a DynamicState (still session-based) and later build a SharedState (spread across multiple sessions). DynamicState would not need any pubsub redis.
Edit: I created a PoC for dynamic and global state: https://github.com/reflex-dev/reflex/pull/3671