浏览代码

improve into component conversion (#4754)

* improve into component conversion

* correct the order of .State
Khaleel Al-Adhami 3 月之前
父节点
当前提交
c6fb4e238d
共有 3 个文件被更改,包括 50 次插入12 次删除
  1. 3 1
      reflex/app.py
  2. 44 11
      reflex/compiler/compiler.py
  3. 3 0
      reflex/state.py

+ 3 - 1
reflex/app.py

@@ -591,7 +591,9 @@ class App(MiddlewareMixin, LifespanMixin):
         Returns:
             The generated component.
         """
-        return component if isinstance(component, Component) else component()
+        from reflex.compiler.compiler import into_component
+
+        return into_component(component)
 
     def add_page(
         self,

+ 44 - 11
reflex/compiler/compiler.py

@@ -4,7 +4,7 @@ from __future__ import annotations
 
 from datetime import datetime
 from pathlib import Path
-from typing import TYPE_CHECKING, Dict, Iterable, Optional, Tuple, Type, Union
+from typing import TYPE_CHECKING, Dict, Iterable, Optional, Sequence, Tuple, Type, Union
 
 from reflex import constants
 from reflex.compiler import templates, utils
@@ -545,7 +545,47 @@ def purge_web_pages_dir():
 
 
 if TYPE_CHECKING:
-    from reflex.app import UnevaluatedPage
+    from reflex.app import ComponentCallable, UnevaluatedPage
+
+
+def _into_component_once(component: Component | ComponentCallable) -> Component | None:
+    """Convert a component to a Component.
+
+    Args:
+        component: The component to convert.
+
+    Returns:
+        The converted component.
+    """
+    if isinstance(component, Component):
+        return component
+    if isinstance(component, (Var, int, float, str)):
+        return Fragment.create(component)
+    if isinstance(component, Sequence):
+        return Fragment.create(*component)
+    return None
+
+
+def into_component(component: Component | ComponentCallable) -> Component:
+    """Convert a component to a Component.
+
+    Args:
+        component: The component to convert.
+
+    Returns:
+        The converted component.
+
+    Raises:
+        TypeError: If the component is not a Component.
+    """
+    if (converted := _into_component_once(component)) is not None:
+        return converted
+    if (
+        callable(component)
+        and (converted := _into_component_once(component())) is not None
+    ):
+        return converted
+    raise TypeError(f"Expected a Component, got {type(component)}")
 
 
 def compile_unevaluated_page(
@@ -568,12 +608,7 @@ def compile_unevaluated_page(
         The compiled component and whether state should be enabled.
     """
     # Generate the component if it is a callable.
-    component = page.component
-    component = component if isinstance(component, Component) else component()
-
-    # unpack components that return tuples in an rx.fragment.
-    if isinstance(component, tuple):
-        component = Fragment.create(*component)
+    component = into_component(page.component)
 
     component._add_style_recursive(style or {}, theme)
 
@@ -678,10 +713,8 @@ class ExecutorSafeFunctions:
             The route, compiled component, and compiled page.
         """
         component, enable_state = compile_unevaluated_page(
-            route, cls.UNCOMPILED_PAGES[route]
+            route, cls.UNCOMPILED_PAGES[route], cls.STATE, style, theme
         )
-        component = component if isinstance(component, Component) else component()
-        component._add_style_recursive(style, theme)
         return route, component, compile_page(route, component, cls.STATE)
 
     @classmethod

+ 3 - 0
reflex/state.py

@@ -2475,6 +2475,8 @@ class ComponentState(State, mixin=True):
         Returns:
             A new instance of the Component with an independent copy of the State.
         """
+        from reflex.compiler.compiler import into_component
+
         cls._per_component_state_instance_count += 1
         state_cls_name = f"{cls.__name__}_n{cls._per_component_state_instance_count}"
         component_state = type(
@@ -2486,6 +2488,7 @@ class ComponentState(State, mixin=True):
         # Save a reference to the dynamic state for pickle/unpickle.
         setattr(reflex.istate.dynamic, state_cls_name, component_state)
         component = component_state.get_component(*children, **props)
+        component = into_component(component)
         component.State = component_state
         return component