Jelajahi Sumber

Improve ClientState compatibility with rx.input (#3490)

* Ignore type checking for generic aliases in _var_name_unwrapped

* Allow ClientStateVar.set_value to be used with text inputs

* client_state: If var_name is not provided, create a random name

* client_state: partition the arg value to get `_e0` from `_e0.target.value`
Masen Furer 11 bulan lalu
induk
melakukan
ffb24ceeee

+ 1 - 1
reflex/components/chakra/forms/input.py

@@ -92,7 +92,7 @@ class Input(ChakraComponent):
         Returns:
             The component.
         """
-        if props.get("value") is not None and props.get("on_change"):
+        if props.get("value") is not None and props.get("on_change") is not None:
             # create a debounced input if the user requests full control to avoid typing jank
             return DebounceInput.create(super().create(*children, **props))
         return super().create(*children, **props)

+ 1 - 1
reflex/components/chakra/forms/textarea.py

@@ -73,7 +73,7 @@ class TextArea(ChakraComponent):
         Returns:
             The component.
         """
-        if props.get("value") is not None and props.get("on_change"):
+        if props.get("value") is not None and props.get("on_change") is not None:
             # create a debounced input if the user requests full control to avoid typing jank
             return DebounceInput.create(super().create(*children, **props))
         return super().create(*children, **props)

+ 1 - 1
reflex/components/radix/themes/components/text_area.py

@@ -107,7 +107,7 @@ class TextArea(RadixThemesComponent, elements.Textarea):
         Returns:
             The component.
         """
-        if props.get("value") is not None and props.get("on_change"):
+        if props.get("value") is not None and props.get("on_change") is not None:
             # create a debounced input if the user requests full control to avoid typing jank
             return DebounceInput.create(super().create(*children, **props))
         return super().create(*children, **props)

+ 1 - 1
reflex/components/radix/themes/components/text_field.py

@@ -100,7 +100,7 @@ class TextFieldRoot(elements.Div, RadixThemesComponent):
             The component.
         """
         component = super().create(*children, **props)
-        if props.get("value") is not None and props.get("on_change"):
+        if props.get("value") is not None and props.get("on_change") is not None:
             # create a debounced input if the user requests full control to avoid typing jank
             return DebounceInput.create(component)
         return component

+ 8 - 3
reflex/experimental/client_state.py

@@ -9,7 +9,7 @@ from typing import Any, Callable, Optional, Type, Union
 from reflex import constants
 from reflex.event import EventChain, EventHandler, EventSpec, call_script
 from reflex.utils.imports import ImportVar
-from reflex.vars import Var, VarData
+from reflex.vars import Var, VarData, get_unique_variable_name
 
 NoValue = object()
 
@@ -75,7 +75,10 @@ class ClientStateVar(Var):
 
     @classmethod
     def create(
-        cls, var_name: str, default: Any = NoValue, global_ref: bool = True
+        cls,
+        var_name: str | None = None,
+        default: Any = NoValue,
+        global_ref: bool = True,
     ) -> "ClientStateVar":
         """Create a local_state Var that can be accessed and updated on the client.
 
@@ -102,6 +105,8 @@ class ClientStateVar(Var):
         Returns:
             ClientStateVar
         """
+        if var_name is None:
+            var_name = get_unique_variable_name()
         assert isinstance(var_name, str), "var_name must be a string."
         if default is NoValue:
             default_var = Var.create_safe("", _var_is_local=False, _var_is_string=False)
@@ -189,7 +194,7 @@ class ClientStateVar(Var):
             # This is a hack to make it work like an EventSpec taking an arg
             value = Var.create_safe(value, _var_is_string=isinstance(value, str))
             if not value._var_is_string and value._var_full_name.startswith("_"):
-                arg = value._var_name_unwrapped
+                arg = value._var_name_unwrapped.partition(".")[0]
             else:
                 arg = ""
             setter = f"({arg}) => {setter}({value._var_name_unwrapped})"

+ 5 - 7
reflex/vars.py

@@ -1792,18 +1792,16 @@ class Var:
         """
         from reflex.style import Style
 
-        type_ = (
-            get_origin(self._var_type)
-            if types.is_generic_alias(self._var_type)
-            else self._var_type
-        )
+        generic_alias = types.is_generic_alias(self._var_type)
+
+        type_ = get_origin(self._var_type) if generic_alias else self._var_type
         wrapped_var = str(self)
 
         return (
             wrapped_var
             if not self._var_state
-            and types._issubclass(type_, dict)
-            or types._issubclass(type_, Style)
+            and not generic_alias
+            and (types._issubclass(type_, dict) or types._issubclass(type_, Style))
             else wrapped_var.strip("{}")
         )