[reflex-web tweaks] Do not memoize children of InputGroup (#2230)

This commit is contained in:
Masen Furer 2023-11-30 09:48:28 -08:00 committed by GitHub
parent a86bcb3c72
commit a2d5bbc133
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 67 additions and 17 deletions

View File

@ -71,6 +71,8 @@ def FormSubmitName():
class FormState(rx.State):
form_data: dict = {}
val: str = "foo"
options: list[str] = ["option1", "option2"]
def form_submit(self, form_data: dict):
self.form_data = form_data
@ -96,15 +98,24 @@ def FormSubmitName():
rx.switch(name="bool_input4"),
rx.slider(name="slider_input"),
rx.range_slider(name="range_input"),
rx.radio_group(["option1", "option2"], name="radio_input"),
rx.select(["option1", "option2"], name="select_input"),
rx.radio_group(FormState.options, name="radio_input"),
rx.select(FormState.options, name="select_input"),
rx.text_area(name="text_area_input"),
rx.input(
name="debounce_input",
debounce_timeout=0,
on_change=rx.console_log,
rx.input_group(
rx.input_left_element(rx.icon(tag="chevron_right")),
rx.input(
name="debounce_input",
debounce_timeout=0,
on_change=rx.console_log,
),
rx.input_right_element(rx.icon(tag="chevron_left")),
),
rx.button_group(
rx.button("Submit", type_="submit"),
rx.icon_button(FormState.val, icon=rx.icon(tag="add")),
variant="outline",
is_attached=True,
),
rx.button("Submit", type_="submit"),
),
on_submit=FormState.form_submit,
custom_attrs={"action": "/invalid"},

View File

@ -23,7 +23,14 @@ from typing import (
from reflex.base import Base
from reflex.compiler.templates import STATEFUL_COMPONENT
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 (
EventChain,
EventHandler,
@ -150,6 +157,9 @@ class Component(BaseComponent, ABC):
# custom attribute
custom_attrs: Dict[str, Union[Var, str]] = {}
# When to memoize this component and its children.
_memoization_mode: MemoizationMode = MemoizationMode()
@classmethod
def __init_subclass__(cls, **kwargs):
"""Set default properties.
@ -1643,14 +1653,13 @@ class StatefulComponent(BaseComponent):
Returns:
The memoized component tree.
"""
from reflex.components.layout.foreach import Foreach
# Foreach must be memoized as a single component to retain index Var context.
if not isinstance(component, Foreach):
component.children = [
cls.compile_from(child) for child in component.children
]
if isinstance(component, Component):
if component._memoization_mode.recursive:
# Recursively memoize stateful children (default).
component.children = [
cls.compile_from(child) for child in component.children
]
# Memoize this component if it depends on state.
stateful_component = cls.create(component)
if stateful_component is not None:
return stateful_component

View File

@ -9,7 +9,7 @@ from reflex.components.libs.chakra import (
LiteralButtonSize,
LiteralInputVariant,
)
from reflex.constants import EventTriggers
from reflex.constants import EventTriggers, MemoizationMode
from reflex.utils import imports
from reflex.vars import Var
@ -107,6 +107,8 @@ class InputGroup(ChakraComponent):
tag = "InputGroup"
_memoization_mode = MemoizationMode(recursive=False)
class InputLeftAddon(ChakraComponent):
"""The InputLeftAddon component is a component that is used to add an addon to the left of an input."""

View File

@ -15,7 +15,7 @@ from reflex.components.libs.chakra import (
LiteralButtonSize,
LiteralInputVariant,
)
from reflex.constants import EventTriggers
from reflex.constants import EventTriggers, MemoizationMode
from reflex.utils import imports
from reflex.vars import Var

View File

@ -8,12 +8,15 @@ from typing import Any, Callable, Iterable
from reflex.components.component import Component
from reflex.components.layout.fragment import Fragment
from reflex.components.tags import IterTag
from reflex.constants import MemoizationMode
from reflex.vars import Var
class Foreach(Component):
"""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.
iterable: Var[Iterable]

View File

@ -25,6 +25,8 @@ from .compiler import (
Ext,
Hooks,
Imports,
MemoizationDisposition,
MemoizationMode,
PageNames,
)
from .config import (
@ -75,6 +77,8 @@ __ALL__ = [
IS_WINDOWS,
LOCAL_STORAGE,
LogLevel,
MemoizationDisposition,
MemoizationMode,
Next,
Node,
NOCOMPILE_FILE,

View File

@ -1,7 +1,9 @@
"""Compiler variables."""
import enum
from enum import Enum
from types import SimpleNamespace
from reflex.base import Base
from reflex.constants import Dirs
from reflex.utils.imports import ImportVar
@ -104,3 +106,21 @@ class Hooks(SimpleNamespace):
"""Common sets of hook declarations."""
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

View File

@ -44,6 +44,7 @@ EXCLUDED_PROPS = [
"is_default",
"special_props",
"_invalid_children",
"_memoization_mode",
"_valid_children",
]