Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[REF-2273] Implement .setvar special EventHandler #3163

Merged
merged 6 commits into from
May 2, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
[REF-2273] Implement .setvar special EventHandler
All State subclasses will now have a special `setvar` EventHandler which
appears in the autocomplete drop down, passes static analysis, and canbe used
to set State Vars in response to event triggers.

Before:
    rx.input(value=State.a, on_change=State.set_a)

After:
    rx.input(value=State.a, on_change=State.setvar("a"))

This reduces the "magic" because `setvar` is statically defined on all State
subclasses.
  • Loading branch information
masenf committed Apr 25, 2024
commit d838deecc54a6daa1808c69d6fdd54c20b4c1fbb
33 changes: 33 additions & 0 deletions reflex/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,9 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
# Whether the state has ever been touched since instantiation.
_was_touched: bool = False

# A special event handler for setting base vars.
setvar: ClassVar[EventHandler]

def __init__(
self,
*args,
Expand Down Expand Up @@ -500,6 +503,9 @@ def __init_subclass__(cls, **kwargs):
value.__qualname__ = f"{cls.__name__}.{name}"
events[name] = value

# Create the setvar event handler for this state
cls._create_setvar()

for name, fn in events.items():
handler = cls._create_event_handler(fn)
cls.event_handlers[name] = handler
Expand Down Expand Up @@ -833,6 +839,33 @@ def _create_event_handler(cls, fn):
"""
return EventHandler(fn=fn, state_full_name=cls.get_full_name())

@classmethod
def _create_setvar(cls):
"""Create the setvar method for the state."""
# Ensure the resulting event handler gets the correct handler name.
_setvar = BaseState._template_setvar
_setvar.__qualname__ = _setvar.__qualname__.replace(
"._template_setvar", ".setvar"
)
cls.event_handlers["setvar"] = cls._create_event_handler(_setvar)
cls.setvar = cls.event_handlers["setvar"]

def _template_setvar(self, var_name: str, value: Any):
"""Set a variable in the state.

Args:
var_name: The name of the variable to set.
value: The value to set the variable to.

Raises:
NameError: If the variable is not found in the state.
"""
if var_name not in self.vars:
raise NameError(
f"Variable {var_name} not found in state {self.get_full_name()}"
)
setattr(self, var_name, value)

@classmethod
def _create_setter(cls, prop: BaseVar):
"""Create a setter for the var.
Expand Down
Loading