implement rx dynamic (#4195)

* implement rx dynamic

* dang it darglint

* add custom type
This commit is contained in:
Khaleel Al-Adhami 2024-10-22 14:27:04 -07:00 committed by GitHub
parent a65fc2e90b
commit 3eab2b6e7d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 53 additions and 0 deletions

View File

@ -331,6 +331,7 @@ _MAPPING: dict = {
"var",
"ComponentState",
"State",
"dynamic",
],
"style": ["Style", "toggle_color_mode"],
"utils.imports": ["ImportVar"],

View File

@ -184,6 +184,7 @@ from .model import session as session
from .page import page as page
from .state import ComponentState as ComponentState
from .state import State as State
from .state import dynamic as dynamic
from .state import var as var
from .style import Style as Style
from .style import toggle_color_mode as toggle_color_mode

View File

@ -30,6 +30,7 @@ from typing import (
Set,
Tuple,
Type,
TypeVar,
Union,
cast,
get_args,
@ -79,6 +80,7 @@ from reflex.utils import console, format, path_ops, prerequisites, types
from reflex.utils.exceptions import (
ComputedVarShadowsBaseVars,
ComputedVarShadowsStateVar,
DynamicComponentInvalidSignature,
DynamicRouteArgShadowsStateVar,
EventHandlerShadowsBuiltInStateMethod,
ImmutableStateError,
@ -2095,6 +2097,51 @@ class State(BaseState):
is_hydrated: bool = False
T = TypeVar("T", bound=BaseState)
def dynamic(func: Callable[[T], Component]):
"""Create a dynamically generated components from a state class.
Args:
func: The function to generate the component.
Returns:
The dynamically generated component.
Raises:
DynamicComponentInvalidSignature: If the function does not have exactly one parameter.
DynamicComponentInvalidSignature: If the function does not have a type hint for the state class.
"""
number_of_parameters = len(inspect.signature(func).parameters)
func_signature = get_type_hints(func)
if "return" in func_signature:
func_signature.pop("return")
values = list(func_signature.values())
if number_of_parameters != 1:
raise DynamicComponentInvalidSignature(
"The function must have exactly one parameter, which is the state class."
)
if len(values) != 1:
raise DynamicComponentInvalidSignature(
"You must provide a type hint for the state class in the function."
)
state_class: Type[T] = values[0]
def wrapper() -> Component:
from reflex.components.base.fragment import fragment
return fragment(state_class._evaluate(lambda state: func(state)))
return wrapper
class FrontendEventExceptionState(State):
"""Substate for handling frontend exceptions."""

View File

@ -139,3 +139,7 @@ class StateSchemaMismatchError(ReflexError, TypeError):
class EnvironmentVarValueError(ReflexError, ValueError):
"""Raised when an environment variable is set to an invalid value."""
class DynamicComponentInvalidSignature(ReflexError, TypeError):
"""Raised when a dynamic component has an invalid signature."""