The case for get_state in @rx.var

The following attempts to make a case for adding support for calling get_state from @rx.var methods. Since I’m not knowledgeable in Reflex internals some of the assumptions made might be incorrect or too simplistic in which case I hope to learn a better way to architect a large reflex application from the responses.

As a Reflex application’s complexity grows it needs to track more attributes in its state. To help manage that state, a developer can break the application state down into smaller substates with each substate containing just a subset of all the application state’s attributes. Reflex uses different subclasses of rx.State created by the developer to manage the different substates of an application session’s state.

Reflex appears to create one instance of each rx.State subclass for each session. When a developer refers to an @rx.var of a rx.State subclass from an rx.Component, reflex provides the data from the instance of that rx.State subclass associated with the session behind the web page displaying the rx.Component. When displaying information on a page, reflex can provide data from the attributes of any of the rx.State subclasses.

When an rx.Component sends an event, the event handler on an rx.State subclass can use self.get_state to fetch any information it needs from other rx.State subclasses. If an application is simple, e.g. an application limited to Create, Read, Update, Delete (CRUD) operations where only the information of one rx.state subclass is ever used at one time, then it is unnecessary to get information between different sub-states. But the moment the application becomes more complex and sub-state objects need to collaborate, then it becomes critical to be able to use information from different substates when handling an event.

Being limited to using get_state only in event handlers forces developers to update related substate objects from all event handlers that change a substate attribute on which there is a dependency causing multiple duplications of dependency propagation code. Instead of a single @rx.var method in the correct substate that references its dependencies in other substates, all event handlers in those other substates need to know there is a downstream dependency and get the appropriate state and set the dependent attributes. Maintenance is far more complex because there is no obvious relationship between the substates in the event handlers so when a developer adds a new event handler that updates a substate attribute with dependencies there is no simple way to know about the dependencies whereas if get_state were possible in @rx.var this logic would only ever be written once and there would be no further need to consider dependencies when adding new events.

The main limitation is how dependency tracking is handled for rx.var. It is much easier to reason about var dependencies in a single inheritance hierarchy (we already don’t allow multiple inheritance for rx.State) as opposed to any arbitrary state class that might be accessed from get_state.

Maintenance is far more complex because there is no obvious relationship between the substates in the event handlers so when a developer adds a new event handler that updates a substate attribute with dependencies there is no simple way to know about the dependencies

This is also what makes it hard for the framework to handle this case.

I also would like to see get_state supported for rx.var, but I don’t know if it will happen any time soon with automatic dep detection. If you’re willing to manually specify your dependency list, then i don’t think there’s any technical limitation to allowing @rx.var to decorate an async function that can call get_state.

That’s an interesting idea.

In my opinion it would be far easier to manually specify the dependencies of the @var than the current option.

That’s because the work would only need to be done once while defining the @var and if it had to be updated then all reachable references would be easy to figure out.

That’s trivial compared to repeating the same logic across multiple event handlers and knowing which event handlers are affected and when to update them.