improve into component conversion (#4754)

* improve into component conversion

* correct the order of .State
This commit is contained in:
Khaleel Al-Adhami 2025-02-13 12:44:42 -08:00 committed by GitHub
parent 10c45b185c
commit c6fb4e238d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 50 additions and 12 deletions

View File

@ -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,

View File

@ -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

View File

@ -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