Browse Source

mixin computed vars should only be applied to highest level state (#3833)

benedikt-bartscher 8 months ago
parent
commit
477e1dece9
2 changed files with 31 additions and 1 deletions
  1. 4 1
      reflex/state.py
  2. 27 0
      tests/test_state.py

+ 4 - 1
reflex/state.py

@@ -431,8 +431,9 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
         return [
             v
             for mixin in cls._mixins() + [cls]
-            for v in mixin.__dict__.values()
+            for name, v in mixin.__dict__.items()
             if isinstance(v, (ComputedVar, ImmutableComputedVar))
+            and name not in cls.inherited_vars
         ]
 
     @classmethod
@@ -560,6 +561,8 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
 
         for mixin in cls._mixins():
             for name, value in mixin.__dict__.items():
+                if name in cls.inherited_vars:
+                    continue
                 if isinstance(value, (ComputedVar, ImmutableComputedVar)):
                     fget = cls._copy_fn(value.fget)
                     newcv = value._replace(

+ 27 - 0
tests/test_state.py

@@ -3161,6 +3161,15 @@ class MixinState(State, mixin=True):
     num: int = 0
     _backend: int = 0
 
+    @rx.var(cache=True)
+    def computed(self) -> str:
+        """A computed var on mixin state.
+
+        Returns:
+            A computed value.
+        """
+        return ""
+
 
 class UsesMixinState(MixinState, State):
     """A state that uses the mixin state."""
@@ -3168,8 +3177,26 @@ class UsesMixinState(MixinState, State):
     pass
 
 
+class ChildUsesMixinState(UsesMixinState):
+    """A child state that uses the mixin state."""
+
+    pass
+
+
 def test_mixin_state() -> None:
     """Test that a mixin state works correctly."""
     assert "num" in UsesMixinState.base_vars
     assert "num" in UsesMixinState.vars
     assert UsesMixinState.backend_vars == {"_backend": 0}
+
+    assert "computed" in UsesMixinState.computed_vars
+    assert "computed" in UsesMixinState.vars
+
+
+def test_child_mixin_state() -> None:
+    """Test that mixin vars are only applied to the highest state in the hierarchy."""
+    assert "num" in ChildUsesMixinState.inherited_vars
+    assert "num" not in ChildUsesMixinState.base_vars
+
+    assert "computed" in ChildUsesMixinState.inherited_vars
+    assert "computed" not in ChildUsesMixinState.computed_vars