ソースを参照

Call event handlers from other event handlers (#691)

Elijah Ahianyo 2 年 前
コミット
592be487c9
3 ファイル変更43 行追加1 行削除
  1. 2 0
      pynecone/app.py
  2. 14 1
      pynecone/state.py
  3. 27 0
      tests/test_state.py

+ 2 - 0
pynecone/app.py

@@ -394,6 +394,8 @@ class App(Base):
         # Compile the custom components.
         compiler.compile_components(custom_components)
 
+        self.state.convert_handlers_to_fns()
+
 
 async def process(
     app: App, event: Event, sid: str, headers: Dict, client_ip: str

+ 14 - 1
pynecone/state.py

@@ -51,6 +51,9 @@ class State(Base, ABC):
     # Backend vars inherited
     inherited_backend_vars: ClassVar[Dict[str, Any]] = {}
 
+    # The event handlers.
+    event_handlers: ClassVar[Dict[str, EventHandler]] = {}
+
     # The parent state.
     parent_state: Optional[State] = None
 
@@ -181,8 +184,18 @@ class State(Base, ABC):
         }
         for name, fn in events.items():
             event_handler = EventHandler(fn=fn)
+            cls.event_handlers[name] = event_handler
             setattr(cls, name, event_handler)
 
+    @classmethod
+    def convert_handlers_to_fns(cls):
+        """Convert the event handlers to functions.
+
+        This is done so the state functions can be called as normal functions during runtime.
+        """
+        for name, event_handler in cls.event_handlers.items():
+            setattr(cls, name, event_handler.fn)
+
     @classmethod
     @functools.lru_cache()
     def get_parent_state(cls) -> Optional[Type[State]]:
@@ -545,7 +558,7 @@ class State(Base, ABC):
         path = event.name.split(".")
         path, name = path[:-1], path[-1]
         substate = self.get_substate(path)
-        handler = getattr(substate, name)
+        handler = substate.event_handlers[name]  # type: ignore
 
         # Process the event.
         fn = functools.partial(handler.fn, substate)

+ 27 - 0
tests/test_state.py

@@ -204,6 +204,33 @@ def test_class_vars(test_state):
     }
 
 
+def test_event_handlers(test_state):
+    """Test that event handler is set correctly.
+
+    Args:
+        test_state: A state.
+    """
+    expected = {
+        "change_both",
+        "do_nothing",
+        "do_something",
+        "set_array",
+        "set_complex",
+        "set_count",
+        "set_fig",
+        "set_key",
+        "set_mapping",
+        "set_num1",
+        "set_num2",
+        "set_obj",
+        "set_value",
+        "set_value2",
+    }
+
+    cls = type(test_state)
+    assert set(cls.event_handlers.keys()).intersection(expected) == expected
+
+
 def test_default_value(test_state):
     """Test that the default value of a var is correct.