[reflex-web tweaks] Do not memoize children of InputGroup (#2230)
This commit is contained in:
parent
a86bcb3c72
commit
a2d5bbc133
@ -71,6 +71,8 @@ def FormSubmitName():
|
|||||||
|
|
||||||
class FormState(rx.State):
|
class FormState(rx.State):
|
||||||
form_data: dict = {}
|
form_data: dict = {}
|
||||||
|
val: str = "foo"
|
||||||
|
options: list[str] = ["option1", "option2"]
|
||||||
|
|
||||||
def form_submit(self, form_data: dict):
|
def form_submit(self, form_data: dict):
|
||||||
self.form_data = form_data
|
self.form_data = form_data
|
||||||
@ -96,15 +98,24 @@ def FormSubmitName():
|
|||||||
rx.switch(name="bool_input4"),
|
rx.switch(name="bool_input4"),
|
||||||
rx.slider(name="slider_input"),
|
rx.slider(name="slider_input"),
|
||||||
rx.range_slider(name="range_input"),
|
rx.range_slider(name="range_input"),
|
||||||
rx.radio_group(["option1", "option2"], name="radio_input"),
|
rx.radio_group(FormState.options, name="radio_input"),
|
||||||
rx.select(["option1", "option2"], name="select_input"),
|
rx.select(FormState.options, name="select_input"),
|
||||||
rx.text_area(name="text_area_input"),
|
rx.text_area(name="text_area_input"),
|
||||||
|
rx.input_group(
|
||||||
|
rx.input_left_element(rx.icon(tag="chevron_right")),
|
||||||
rx.input(
|
rx.input(
|
||||||
name="debounce_input",
|
name="debounce_input",
|
||||||
debounce_timeout=0,
|
debounce_timeout=0,
|
||||||
on_change=rx.console_log,
|
on_change=rx.console_log,
|
||||||
),
|
),
|
||||||
|
rx.input_right_element(rx.icon(tag="chevron_left")),
|
||||||
|
),
|
||||||
|
rx.button_group(
|
||||||
rx.button("Submit", type_="submit"),
|
rx.button("Submit", type_="submit"),
|
||||||
|
rx.icon_button(FormState.val, icon=rx.icon(tag="add")),
|
||||||
|
variant="outline",
|
||||||
|
is_attached=True,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
on_submit=FormState.form_submit,
|
on_submit=FormState.form_submit,
|
||||||
custom_attrs={"action": "/invalid"},
|
custom_attrs={"action": "/invalid"},
|
||||||
|
@ -23,7 +23,14 @@ from typing import (
|
|||||||
from reflex.base import Base
|
from reflex.base import Base
|
||||||
from reflex.compiler.templates import STATEFUL_COMPONENT
|
from reflex.compiler.templates import STATEFUL_COMPONENT
|
||||||
from reflex.components.tags import Tag
|
from reflex.components.tags import Tag
|
||||||
from reflex.constants import Dirs, EventTriggers, Hooks, Imports, PageNames
|
from reflex.constants import (
|
||||||
|
Dirs,
|
||||||
|
EventTriggers,
|
||||||
|
Hooks,
|
||||||
|
Imports,
|
||||||
|
MemoizationMode,
|
||||||
|
PageNames,
|
||||||
|
)
|
||||||
from reflex.event import (
|
from reflex.event import (
|
||||||
EventChain,
|
EventChain,
|
||||||
EventHandler,
|
EventHandler,
|
||||||
@ -150,6 +157,9 @@ class Component(BaseComponent, ABC):
|
|||||||
# custom attribute
|
# custom attribute
|
||||||
custom_attrs: Dict[str, Union[Var, str]] = {}
|
custom_attrs: Dict[str, Union[Var, str]] = {}
|
||||||
|
|
||||||
|
# When to memoize this component and its children.
|
||||||
|
_memoization_mode: MemoizationMode = MemoizationMode()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def __init_subclass__(cls, **kwargs):
|
def __init_subclass__(cls, **kwargs):
|
||||||
"""Set default properties.
|
"""Set default properties.
|
||||||
@ -1643,14 +1653,13 @@ class StatefulComponent(BaseComponent):
|
|||||||
Returns:
|
Returns:
|
||||||
The memoized component tree.
|
The memoized component tree.
|
||||||
"""
|
"""
|
||||||
from reflex.components.layout.foreach import Foreach
|
if isinstance(component, Component):
|
||||||
|
if component._memoization_mode.recursive:
|
||||||
# Foreach must be memoized as a single component to retain index Var context.
|
# Recursively memoize stateful children (default).
|
||||||
if not isinstance(component, Foreach):
|
|
||||||
component.children = [
|
component.children = [
|
||||||
cls.compile_from(child) for child in component.children
|
cls.compile_from(child) for child in component.children
|
||||||
]
|
]
|
||||||
if isinstance(component, Component):
|
# Memoize this component if it depends on state.
|
||||||
stateful_component = cls.create(component)
|
stateful_component = cls.create(component)
|
||||||
if stateful_component is not None:
|
if stateful_component is not None:
|
||||||
return stateful_component
|
return stateful_component
|
||||||
|
@ -9,7 +9,7 @@ from reflex.components.libs.chakra import (
|
|||||||
LiteralButtonSize,
|
LiteralButtonSize,
|
||||||
LiteralInputVariant,
|
LiteralInputVariant,
|
||||||
)
|
)
|
||||||
from reflex.constants import EventTriggers
|
from reflex.constants import EventTriggers, MemoizationMode
|
||||||
from reflex.utils import imports
|
from reflex.utils import imports
|
||||||
from reflex.vars import Var
|
from reflex.vars import Var
|
||||||
|
|
||||||
@ -107,6 +107,8 @@ class InputGroup(ChakraComponent):
|
|||||||
|
|
||||||
tag = "InputGroup"
|
tag = "InputGroup"
|
||||||
|
|
||||||
|
_memoization_mode = MemoizationMode(recursive=False)
|
||||||
|
|
||||||
|
|
||||||
class InputLeftAddon(ChakraComponent):
|
class InputLeftAddon(ChakraComponent):
|
||||||
"""The InputLeftAddon component is a component that is used to add an addon to the left of an input."""
|
"""The InputLeftAddon component is a component that is used to add an addon to the left of an input."""
|
||||||
|
@ -15,7 +15,7 @@ from reflex.components.libs.chakra import (
|
|||||||
LiteralButtonSize,
|
LiteralButtonSize,
|
||||||
LiteralInputVariant,
|
LiteralInputVariant,
|
||||||
)
|
)
|
||||||
from reflex.constants import EventTriggers
|
from reflex.constants import EventTriggers, MemoizationMode
|
||||||
from reflex.utils import imports
|
from reflex.utils import imports
|
||||||
from reflex.vars import Var
|
from reflex.vars import Var
|
||||||
|
|
||||||
|
@ -8,12 +8,15 @@ from typing import Any, Callable, Iterable
|
|||||||
from reflex.components.component import Component
|
from reflex.components.component import Component
|
||||||
from reflex.components.layout.fragment import Fragment
|
from reflex.components.layout.fragment import Fragment
|
||||||
from reflex.components.tags import IterTag
|
from reflex.components.tags import IterTag
|
||||||
|
from reflex.constants import MemoizationMode
|
||||||
from reflex.vars import Var
|
from reflex.vars import Var
|
||||||
|
|
||||||
|
|
||||||
class Foreach(Component):
|
class Foreach(Component):
|
||||||
"""A component that takes in an iterable and a render function and renders a list of components."""
|
"""A component that takes in an iterable and a render function and renders a list of components."""
|
||||||
|
|
||||||
|
_memoization_mode = MemoizationMode(recursive=False)
|
||||||
|
|
||||||
# The iterable to create components from.
|
# The iterable to create components from.
|
||||||
iterable: Var[Iterable]
|
iterable: Var[Iterable]
|
||||||
|
|
||||||
|
@ -25,6 +25,8 @@ from .compiler import (
|
|||||||
Ext,
|
Ext,
|
||||||
Hooks,
|
Hooks,
|
||||||
Imports,
|
Imports,
|
||||||
|
MemoizationDisposition,
|
||||||
|
MemoizationMode,
|
||||||
PageNames,
|
PageNames,
|
||||||
)
|
)
|
||||||
from .config import (
|
from .config import (
|
||||||
@ -75,6 +77,8 @@ __ALL__ = [
|
|||||||
IS_WINDOWS,
|
IS_WINDOWS,
|
||||||
LOCAL_STORAGE,
|
LOCAL_STORAGE,
|
||||||
LogLevel,
|
LogLevel,
|
||||||
|
MemoizationDisposition,
|
||||||
|
MemoizationMode,
|
||||||
Next,
|
Next,
|
||||||
Node,
|
Node,
|
||||||
NOCOMPILE_FILE,
|
NOCOMPILE_FILE,
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
"""Compiler variables."""
|
"""Compiler variables."""
|
||||||
|
import enum
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from types import SimpleNamespace
|
from types import SimpleNamespace
|
||||||
|
|
||||||
|
from reflex.base import Base
|
||||||
from reflex.constants import Dirs
|
from reflex.constants import Dirs
|
||||||
from reflex.utils.imports import ImportVar
|
from reflex.utils.imports import ImportVar
|
||||||
|
|
||||||
@ -104,3 +106,21 @@ class Hooks(SimpleNamespace):
|
|||||||
"""Common sets of hook declarations."""
|
"""Common sets of hook declarations."""
|
||||||
|
|
||||||
EVENTS = f"const [{CompileVars.ADD_EVENTS}, {CompileVars.CONNECT_ERROR}] = useContext(EventLoopContext);"
|
EVENTS = f"const [{CompileVars.ADD_EVENTS}, {CompileVars.CONNECT_ERROR}] = useContext(EventLoopContext);"
|
||||||
|
|
||||||
|
|
||||||
|
class MemoizationDisposition(enum.Enum):
|
||||||
|
"""The conditions under which a component should be memoized."""
|
||||||
|
|
||||||
|
# If the component uses state or events, it should be memoized.
|
||||||
|
STATEFUL = "stateful"
|
||||||
|
# TODO: add more modes, like always and never
|
||||||
|
|
||||||
|
|
||||||
|
class MemoizationMode(Base):
|
||||||
|
"""The mode for memoizing a Component."""
|
||||||
|
|
||||||
|
# The conditions under which the component should be memoized.
|
||||||
|
disposition: MemoizationDisposition = MemoizationDisposition.STATEFUL
|
||||||
|
|
||||||
|
# Whether children of this component should be memoized first.
|
||||||
|
recursive: bool = True
|
||||||
|
@ -44,6 +44,7 @@ EXCLUDED_PROPS = [
|
|||||||
"is_default",
|
"is_default",
|
||||||
"special_props",
|
"special_props",
|
||||||
"_invalid_children",
|
"_invalid_children",
|
||||||
|
"_memoization_mode",
|
||||||
"_valid_children",
|
"_valid_children",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user