Procházet zdrojové kódy

deprecate Component __init__ (#4904)

* deprecate Component __init__

* add hot loop for _unsafe_create

* maybe ?

* precommit

* class vars all the way and improve style

* we can't have memoization mode

* optimize var checks inside of components

* use default factory ??

* is functools faster than lambda?

* handle private annotated assignments
Khaleel Al-Adhami před 2 měsíci
rodič
revize
c08d6986e6
29 změnil soubory, kde provedl 252 přidání a 196 odebrání
  1. 3 3
      reflex/components/base/bare.py
  2. 86 42
      reflex/components/component.py
  3. 7 16
      reflex/components/core/cond.py
  4. 1 1
      reflex/components/core/debounce.py
  5. 2 1
      reflex/components/core/foreach.py
  6. 6 8
      reflex/components/core/match.py
  7. 1 1
      reflex/components/gridjs/datatable.py
  8. 4 4
      reflex/components/radix/primitives/accordion.py
  9. 2 2
      reflex/components/radix/themes/base.py
  10. 0 3
      reflex/components/radix/themes/color_mode.pyi
  11. 12 9
      reflex/components/radix/themes/components/context_menu.py
  12. 10 7
      reflex/components/radix/themes/components/dropdown_menu.py
  13. 2 2
      reflex/components/radix/themes/components/radio_cards.py
  14. 2 2
      reflex/components/radix/themes/components/segmented_control.py
  15. 5 5
      reflex/components/radix/themes/components/select.py
  16. 9 9
      reflex/components/radix/themes/components/table.py
  17. 2 2
      reflex/components/radix/themes/components/tabs.py
  18. 2 2
      reflex/components/radix/themes/layout/flex.py
  19. 2 2
      reflex/components/radix/themes/layout/grid.py
  20. 9 9
      reflex/components/recharts/cartesian.py
  21. 10 10
      reflex/components/recharts/charts.py
  22. 2 2
      reflex/components/recharts/general.py
  23. 7 7
      reflex/components/recharts/polar.py
  24. 7 1
      reflex/style.py
  25. 6 0
      reflex/utils/pyi_generator.py
  26. 2 2
      tests/units/components/core/test_banner.py
  27. 3 3
      tests/units/components/core/test_cond.py
  28. 1 1
      tests/units/components/core/test_debounce.py
  29. 47 40
      tests/units/components/test_component.py

+ 3 - 3
reflex/components/base/bare.py

@@ -70,13 +70,13 @@ class Bare(Component):
         if isinstance(contents, Var):
             if isinstance(contents, LiteralStringVar):
                 validate_str(contents._var_value)
-            return cls(contents=contents)
+            return cls._unsafe_create(children=[], contents=contents)
         else:
             if isinstance(contents, str):
                 validate_str(contents)
-            contents = str(contents) if contents is not None else ""
+            contents = Var.create(contents if contents is not None else "")
 
-        return cls._create(children=[], contents=contents)
+        return cls._unsafe_create(children=[], contents=contents)
 
     def _get_all_hooks_internal(self) -> dict[str, VarData | None]:
         """Include the hooks for the component.

+ 86 - 42
reflex/components/component.py

@@ -4,6 +4,7 @@ from __future__ import annotations
 
 import copy
 import dataclasses
+import functools
 import inspect
 import typing
 from abc import ABC, abstractmethod
@@ -25,6 +26,9 @@ from typing import (
     get_origin,
 )
 
+import pydantic.v1
+import pydantic.v1.fields
+
 import reflex.state
 from reflex.base import Base
 from reflex.compiler.templates import STATEFUL_COMPONENT
@@ -73,19 +77,19 @@ class BaseComponent(Base, ABC):
     """
 
     # The children nested within the component.
-    children: list[BaseComponent] = []
+    children: list[BaseComponent] = pydantic.v1.Field(default_factory=list)
 
     # The library that the component is based on.
-    library: str | None = None
+    library: str | None = pydantic.v1.Field(default_factory=lambda: None)
 
     # List here the non-react dependency needed by `library`
-    lib_dependencies: list[str] = []
+    lib_dependencies: list[str] = pydantic.v1.Field(default_factory=list)
 
     # List here the dependencies that need to be transpiled by Next.js
-    transpile_packages: list[str] = []
+    transpile_packages: list[str] = pydantic.v1.Field(default_factory=list)
 
     # The tag to use when rendering the component.
-    tag: str | None = None
+    tag: str | None = pydantic.v1.Field(default_factory=lambda: None)
 
     @abstractmethod
     def render(self) -> dict:
@@ -262,52 +266,56 @@ class Component(BaseComponent, ABC):
     """A component with style, event trigger and other props."""
 
     # The style of the component.
-    style: Style = Style()
+    style: Style = pydantic.v1.Field(default_factory=Style)
 
     # A mapping from event triggers to event chains.
-    event_triggers: dict[str, EventChain | Var] = {}
+    event_triggers: dict[str, EventChain | Var] = pydantic.v1.Field(
+        default_factory=dict
+    )
 
     # The alias for the tag.
-    alias: str | None = None
+    alias: str | None = pydantic.v1.Field(default_factory=lambda: None)
 
     # Whether the import is default or named.
-    is_default: bool | None = False
+    is_default: bool | None = pydantic.v1.Field(default_factory=lambda: False)
 
     # A unique key for the component.
-    key: Any = None
+    key: Any = pydantic.v1.Field(default_factory=lambda: None)
 
     # The id for the component.
-    id: Any = None
+    id: Any = pydantic.v1.Field(default_factory=lambda: None)
 
     # The class name for the component.
-    class_name: Any = None
+    class_name: Any = pydantic.v1.Field(default_factory=lambda: None)
 
     # Special component props.
-    special_props: list[Var] = []
+    special_props: list[Var] = pydantic.v1.Field(default_factory=list)
 
     # Whether the component should take the focus once the page is loaded
-    autofocus: bool = False
+    autofocus: bool = pydantic.v1.Field(default_factory=lambda: False)
 
     # components that cannot be children
-    _invalid_children: list[str] = []
+    _invalid_children: ClassVar[list[str]] = []
 
     # only components that are allowed as children
-    _valid_children: list[str] = []
+    _valid_children: ClassVar[list[str]] = []
 
     # only components that are allowed as parent
-    _valid_parents: list[str] = []
+    _valid_parents: ClassVar[list[str]] = []
 
     # props to change the name of
-    _rename_props: dict[str, str] = {}
+    _rename_props: ClassVar[dict[str, str]] = {}
 
     # custom attribute
-    custom_attrs: dict[str, Var | Any] = {}
+    custom_attrs: dict[str, Var | Any] = pydantic.v1.Field(default_factory=dict)
 
     # When to memoize this component and its children.
     _memoization_mode: MemoizationMode = MemoizationMode()
 
     # State class associated with this component instance
-    State: Type[reflex.state.State] | None = None
+    State: Type[reflex.state.State] | None = pydantic.v1.Field(
+        default_factory=lambda: None
+    )
 
     def add_imports(self) -> ImportDict | list[ImportDict]:
         """Add imports for the component.
@@ -412,16 +420,14 @@ class Component(BaseComponent, ABC):
             if field.name not in props:
                 continue
 
-            field_type = types.value_inside_optional(
-                types.get_field_type(cls, field.name)
-            )
-
             # Set default values for any props.
-            if types._issubclass(field_type, Var):
+            if field.type_ is Var:
                 field.required = False
                 if field.default is not None:
-                    field.default = LiteralVar.create(field.default)
-            elif types._issubclass(field_type, EventHandler):
+                    field.default_factory = functools.partial(
+                        LiteralVar.create, field.default
+                    )
+            elif field.type_ is EventHandler:
                 field.required = False
 
         # Ensure renamed props from parent classes are applied to the subclass.
@@ -432,6 +438,23 @@ class Component(BaseComponent, ABC):
                     inherited_rename_props.update(parent._rename_props)
             cls._rename_props = inherited_rename_props
 
+    def __init__(self, **kwargs):
+        """Initialize the custom component.
+
+        Args:
+            **kwargs: The kwargs to pass to the component.
+        """
+        console.deprecate(
+            "component-direct-instantiation",
+            reason="Use the `create` method instead.",
+            deprecation_version="0.7.2",
+            removal_version="0.8.0",
+        )
+        super().__init__(
+            children=kwargs.get("children", []),
+        )
+        self._post_init(**kwargs)
+
     def _post_init(self, *args, **kwargs):
         """Initialize the component.
 
@@ -472,13 +495,10 @@ class Component(BaseComponent, ABC):
                 )
             if key in component_specific_triggers:
                 # Event triggers are bound to event chains.
-                field_type = EventChain
+                is_var = False
             elif key in props:
                 # Set the field type.
-                field_type = types.value_inside_optional(
-                    types.get_field_type(type(self), key)
-                )
-
+                is_var = field.type_ is Var if (field := fields.get(key)) else False
             else:
                 continue
 
@@ -493,7 +513,7 @@ class Component(BaseComponent, ABC):
                 return key
 
             # Check whether the key is a component prop.
-            if types._issubclass(field_type, Var):
+            if is_var:
                 try:
                     kwargs[key] = determine_key(value)
 
@@ -565,9 +585,15 @@ class Component(BaseComponent, ABC):
                 "&": style,
             }
 
+        fields_style = self.get_fields()["style"]
+
         kwargs["style"] = Style(
             {
-                **self.get_fields()["style"].default,
+                **(
+                    fields_style.default_factory()
+                    if fields_style.default_factory
+                    else fields_style.default
+                ),
                 **style,
                 **{attr: value for attr, value in kwargs.items() if attr not in fields},
             }
@@ -779,7 +805,7 @@ class Component(BaseComponent, ABC):
         # Validate all the children.
         validate_children(children)
 
-        children = [
+        children_normalized = [
             (
                 child
                 if isinstance(child, Component)
@@ -792,10 +818,10 @@ class Component(BaseComponent, ABC):
             for child in children
         ]
 
-        return cls._create(children, **props)
+        return cls._create(children_normalized, **props)
 
     @classmethod
-    def _create(cls: Type[T], children: list[Component], **props: Any) -> T:
+    def _create(cls: Type[T], children: Sequence[BaseComponent], **props: Any) -> T:
         """Create the component.
 
         Args:
@@ -805,8 +831,26 @@ class Component(BaseComponent, ABC):
         Returns:
             The component.
         """
-        comp = cls.construct(id=props.get("id"), children=children)
-        comp._post_init(children=children, **props)
+        comp = cls.construct(id=props.get("id"), children=list(children))
+        comp._post_init(children=list(children), **props)
+        return comp
+
+    @classmethod
+    def _unsafe_create(
+        cls: Type[T], children: Sequence[BaseComponent], **props: Any
+    ) -> T:
+        """Create the component without running post_init.
+
+        Args:
+            children: The children of the component.
+            **props: The props of the component.
+
+        Returns:
+            The component.
+        """
+        comp = cls.construct(id=props.get("id"), children=list(children))
+        for prop, value in props.items():
+            setattr(comp, prop, value)
         return comp
 
     def add_style(self) -> dict[str, Any] | None:
@@ -991,8 +1035,8 @@ class Component(BaseComponent, ABC):
                     validate_child(c)
 
             if isinstance(child, Cond):
-                validate_child(child.comp1)
-                validate_child(child.comp2)
+                validate_child(child.children[0])
+                validate_child(child.children[1])
 
             if isinstance(child, Match):
                 for cases in child.match_cases:
@@ -1769,7 +1813,7 @@ class CustomComponent(Component):
             type_ = props_types[key]
 
             # Handle event chains.
-            if types._issubclass(type_, EventActionsMixin):
+            if type_ is EventHandler:
                 inspect.getfullargspec(component_fn).annotations[key]
                 self.props[camel_cased_key] = EventChain.create(
                     value=value, args_spec=get_args_spec(key), key=key

+ 7 - 16
reflex/components/core/cond.py

@@ -26,11 +26,6 @@ class Cond(MemoizationLeaf):
     # The cond to determine which component to render.
     cond: Var[Any]
 
-    # The component to render if the cond is true.
-    comp1: BaseComponent | None = None
-    # The component to render if the cond is false.
-    comp2: BaseComponent | None = None
-
     @classmethod
     def create(
         cls,
@@ -54,19 +49,17 @@ class Cond(MemoizationLeaf):
         if comp2 is None or type(comp2).__name__ != "Fragment":
             comp2 = Fragment.create(comp2) if comp2 else Fragment.create()
         return Fragment.create(
-            cls(
-                cond=cond,
-                comp1=comp1,
-                comp2=comp2,
+            cls._create(
                 children=[comp1, comp2],
+                cond=cond,
             )
         )
 
     def _render(self) -> Tag:
         return CondTag(
             cond=self.cond,
-            true_value=self.comp1.render(),  # pyright: ignore [reportOptionalMemberAccess]
-            false_value=self.comp2.render(),  # pyright: ignore [reportOptionalMemberAccess]
+            true_value=self.children[0].render(),
+            false_value=self.children[1].render(),
         )
 
     def render(self) -> Dict:
@@ -86,7 +79,7 @@ class Cond(MemoizationLeaf):
             ).set(
                 props=tag.format_props(),
             ),
-            cond_state=f"isTrue({self.cond!s})",
+            cond_state=str(self.cond),
         )
 
     def add_imports(self) -> ImportDict:
@@ -137,7 +130,7 @@ def cond(condition: Any, c1: Any, c2: Any = None) -> Component | Var:
     if isinstance(c1, BaseComponent):
         if c2 is not None and not isinstance(c2, BaseComponent):
             raise ValueError("Both arguments must be components.")
-        return Cond.create(cond_var, c1, c2)
+        return Cond.create(cond_var.bool(), c1, c2)
 
     # Otherwise, create a conditional Var.
     # Check that the second argument is valid.
@@ -155,9 +148,7 @@ def cond(condition: Any, c1: Any, c2: Any = None) -> Component | Var:
 
     # Create the conditional var.
     return ternary_operation(
-        cond_var.bool()._replace(
-            merge_var_data=VarData(imports=_IS_TRUE_IMPORT),
-        ),
+        cond_var.bool(),
         c1_var,
         c2_var,
     )

+ 1 - 1
reflex/components/core/debounce.py

@@ -127,7 +127,7 @@ class DebounceInput(Component):
         component._get_style = child._get_style
         component.event_triggers.update(child.event_triggers)
         component.children = child.children
-        component._rename_props = child._rename_props
+        component._rename_props = child._rename_props  # pyright: ignore[reportAttributeAccessIssue]
         outer_get_all_custom_code = component._get_all_custom_code
         component._get_all_custom_code = lambda: outer_get_all_custom_code().union(
             child._get_all_custom_code()

+ 2 - 1
reflex/components/core/foreach.py

@@ -90,7 +90,8 @@ class Foreach(Component):
         if types.is_optional(iterable._var_type):
             iterable = cond(iterable, iterable, [])
 
-        component = cls(
+        component = cls._create(
+            children=[],
             iterable=iterable,
             render_fn=render_fn,
         )

+ 6 - 8
reflex/components/core/match.py

@@ -7,7 +7,7 @@ from reflex.components.base import Fragment
 from reflex.components.component import BaseComponent, Component, MemoizationLeaf
 from reflex.components.tags import MatchTag, Tag
 from reflex.style import Style
-from reflex.utils import format, types
+from reflex.utils import format
 from reflex.utils.exceptions import MatchTypeError
 from reflex.utils.imports import ImportDict
 from reflex.vars import VarData
@@ -46,7 +46,7 @@ class Match(MemoizationLeaf):
 
         cls._validate_return_types(match_cases)
 
-        if default is None and types._issubclass(type(match_cases[0][-1]), Var):
+        if default is None and isinstance(match_cases[0][-1], Var):
             raise ValueError(
                 "For cases with return types as Vars, a default case must be provided"
             )
@@ -182,7 +182,7 @@ class Match(MemoizationLeaf):
             return_type = Var
 
         for index, case in enumerate(match_cases):
-            if not types._issubclass(type(case[-1]), return_type):
+            if not isinstance(case[-1], return_type):
                 raise MatchTypeError(
                     f"Match cases should have the same return types. Case {index} with return "
                     f"value `{case[-1]._js_expr if isinstance(case[-1], Var) else textwrap.shorten(str(case[-1]), width=250)}`"
@@ -209,14 +209,12 @@ class Match(MemoizationLeaf):
         Raises:
             ValueError: If the return types are not vars when creating a match var for Var types.
         """
-        if default is None and types._issubclass(
-            type(match_cases[0][-1]), BaseComponent
-        ):
+        if default is None and isinstance(match_cases[0][-1], BaseComponent):
             default = Fragment.create()
 
-        if types._issubclass(type(match_cases[0][-1]), BaseComponent):
+        if isinstance(match_cases[0][-1], BaseComponent):
             return Fragment.create(
-                cls(
+                cls._create(
                     cond=match_cond_var,
                     match_cases=match_cases,
                     default=default,

+ 1 - 1
reflex/components/gridjs/datatable.py

@@ -91,7 +91,7 @@ class DataTable(Gridjs):
         # If data is a list and columns are not provided, throw an error
         if (
             (isinstance(data, Var) and types._issubclass(data._var_type, List))
-            or issubclass(type(data), List)
+            or isinstance(data, list)
         ) and columns is None:
             raise ValueError(
                 "column field should be specified when the data field is a list type"

+ 4 - 4
reflex/components/radix/primitives/accordion.py

@@ -2,7 +2,7 @@
 
 from __future__ import annotations
 
-from typing import Any, Literal, Sequence
+from typing import Any, ClassVar, Literal, Sequence
 
 from reflex.components.component import Component, ComponentNamespace
 from reflex.components.core.colors import color
@@ -124,7 +124,7 @@ class AccordionRoot(AccordionComponent):
     # Whether to show divider lines between items.
     show_dividers: Var[bool]
 
-    _valid_children: list[str] = ["AccordionItem"]
+    _valid_children: ClassVar[list[str]] = ["AccordionItem"]
 
     # Fired when the opened the accordions changes.
     on_value_change: EventHandler[on_value_change]
@@ -201,13 +201,13 @@ class AccordionItem(AccordionComponent):
     # The content of the accordion item.
     content: Var[Component | str | None] = Var.create(None)
 
-    _valid_children: list[str] = [
+    _valid_children: ClassVar[list[str]] = [
         "AccordionHeader",
         "AccordionTrigger",
         "AccordionContent",
     ]
 
-    _valid_parents: list[str] = ["AccordionRoot"]
+    _valid_parents: ClassVar[list[str]] = ["AccordionRoot"]
 
     @classmethod
     def create(

+ 2 - 2
reflex/components/radix/themes/base.py

@@ -2,7 +2,7 @@
 
 from __future__ import annotations
 
-from typing import Any, Literal
+from typing import Any, ClassVar, Literal
 
 from reflex.components import Component
 from reflex.components.core.breakpoints import Responsive
@@ -113,7 +113,7 @@ class RadixThemesComponent(Component):
     library = "@radix-ui/themes@^3.2.1"
 
     # "Fake" prop color_scheme is used to avoid shadowing CSS prop "color".
-    _rename_props: dict[str, str] = {"colorScheme": "color"}
+    _rename_props: ClassVar[dict[str, str]] = {"colorScheme": "color"}
 
     @classmethod
     def create(

+ 0 - 3
reflex/components/radix/themes/color_mode.pyi

@@ -5,7 +5,6 @@
 # ------------------------------------------------------
 from typing import Any, Literal, Optional, overload
 
-from reflex.components.component import BaseComponent
 from reflex.components.core.breakpoints import Breakpoints
 from reflex.components.core.cond import Cond
 from reflex.components.lucide.icon import Icon
@@ -26,8 +25,6 @@ class ColorModeIcon(Cond):
         cls,
         *children,
         cond: Any | Var[Any] | None = None,
-        comp1: BaseComponent | None = None,
-        comp2: BaseComponent | None = None,
         style: Style | None = None,
         key: Any | None = None,
         id: Any | None = None,

+ 12 - 9
reflex/components/radix/themes/components/context_menu.py

@@ -1,6 +1,6 @@
 """Interactive components provided by @radix-ui/themes."""
 
-from typing import Literal
+from typing import ClassVar, Literal
 
 from reflex.components.component import ComponentNamespace
 from reflex.components.core.breakpoints import Responsive
@@ -36,7 +36,7 @@ class ContextMenuRoot(RadixThemesComponent):
     # The modality of the context menu. When set to true, interaction with outside elements will be disabled and only menu content will be visible to screen readers.
     modal: Var[bool]
 
-    _invalid_children: list[str] = ["ContextMenuItem"]
+    _invalid_children: ClassVar[list[str]] = ["ContextMenuItem"]
 
     # Fired when the open state changes.
     on_open_change: EventHandler[passthrough_event_spec(bool)]
@@ -53,9 +53,9 @@ class ContextMenuTrigger(RadixThemesComponent):
     # Whether the trigger is disabled
     disabled: Var[bool]
 
-    _valid_parents: list[str] = ["ContextMenuRoot"]
+    _valid_parents: ClassVar[list[str]] = ["ContextMenuRoot"]
 
-    _invalid_children: list[str] = ["ContextMenuContent"]
+    _invalid_children: ClassVar[list[str]] = ["ContextMenuContent"]
 
     _memoization_mode = MemoizationMode(recursive=False)
 
@@ -155,7 +155,7 @@ class ContextMenuSubTrigger(RadixThemesComponent):
     # Optional text used for typeahead purposes. By default the typeahead behavior will use the .textContent of the item. Use this when the content is complex, or you have non-textual content inside.
     text_value: Var[str]
 
-    _valid_parents: list[str] = ["ContextMenuContent", "ContextMenuSub"]
+    _valid_parents: ClassVar[list[str]] = ["ContextMenuContent", "ContextMenuSub"]
 
     _memoization_mode = MemoizationMode(recursive=False)
 
@@ -192,7 +192,7 @@ class ContextMenuSubContent(RadixThemesComponent):
     # Whether to hide the content when the trigger becomes fully occluded. Defaults to False.
     hide_when_detached: Var[bool]
 
-    _valid_parents: list[str] = ["ContextMenuSub"]
+    _valid_parents: ClassVar[list[str]] = ["ContextMenuSub"]
 
     # Fired when the escape key is pressed.
     on_escape_key_down: EventHandler[no_args_event_spec]
@@ -227,7 +227,7 @@ class ContextMenuItem(RadixThemesComponent):
     # Optional text used for typeahead purposes. By default the typeahead behavior will use the content of the item. Use this when the content is complex, or you have non-textual content inside.
     text_value: Var[str]
 
-    _valid_parents: list[str] = [
+    _valid_parents: ClassVar[list[str]] = [
         "ContextMenuContent",
         "ContextMenuSubContent",
         "ContextMenuGroup",
@@ -269,7 +269,10 @@ class ContextMenuGroup(RadixThemesComponent):
     # Change the default rendered element for the one passed as a child, merging their props and behavior. Defaults to False.
     as_child: Var[bool]
 
-    _valid_parents: list[str] = ["ContextMenuContent", "ContextMenuSubContent"]
+    _valid_parents: ClassVar[list[str]] = [
+        "ContextMenuContent",
+        "ContextMenuSubContent",
+    ]
 
 
 class ContextMenuRadioGroup(RadixThemesComponent):
@@ -289,7 +292,7 @@ class ContextMenuRadioGroup(RadixThemesComponent):
     # Fired when the value of the radio group changes.
     on_change: EventHandler[passthrough_event_spec(str)]
 
-    _valid_parents: list[str] = [
+    _valid_parents: ClassVar[list[str]] = [
         "ContextMenuRadioItem",
         "ContextMenuSubContent",
         "ContextMenuContent",

+ 10 - 7
reflex/components/radix/themes/components/dropdown_menu.py

@@ -1,6 +1,6 @@
 """Interactive components provided by @radix-ui/themes."""
 
-from typing import Literal
+from typing import ClassVar, Literal
 
 from reflex.components.component import ComponentNamespace
 from reflex.components.core.breakpoints import Responsive
@@ -43,7 +43,7 @@ class DropdownMenuRoot(RadixThemesComponent):
     # The reading direction of submenus when applicable. If omitted, inherits globally from DirectionProvider or assumes LTR (left-to-right) reading mode.
     dir: Var[LiteralDirType]
 
-    _invalid_children: list[str] = ["DropdownMenuItem"]
+    _invalid_children: ClassVar[list[str]] = ["DropdownMenuItem"]
 
     # Fired when the open state changes.
     on_open_change: EventHandler[passthrough_event_spec(bool)]
@@ -57,9 +57,9 @@ class DropdownMenuTrigger(RadixThemesTriggerComponent):
     # Change the default rendered element for the one passed as a child, merging their props and behavior. Defaults to False.
     as_child: Var[bool]
 
-    _valid_parents: list[str] = ["DropdownMenuRoot"]
+    _valid_parents: ClassVar[list[str]] = ["DropdownMenuRoot"]
 
-    _invalid_children: list[str] = ["DropdownMenuContent"]
+    _invalid_children: ClassVar[list[str]] = ["DropdownMenuContent"]
 
     _memoization_mode = MemoizationMode(recursive=False)
 
@@ -144,7 +144,7 @@ class DropdownMenuSubTrigger(RadixThemesTriggerComponent):
     # Optional text used for typeahead purposes. By default the typeahead behavior will use the .textContent of the item. Use this when the content is complex, or you have non-textual content inside.
     text_value: Var[str]
 
-    _valid_parents: list[str] = ["DropdownMenuContent", "DropdownMenuSub"]
+    _valid_parents: ClassVar[list[str]] = ["DropdownMenuContent", "DropdownMenuSub"]
 
     _memoization_mode = MemoizationMode(recursive=False)
 
@@ -196,7 +196,7 @@ class DropdownMenuSubContent(RadixThemesComponent):
     # Whether to hide the content when the trigger becomes fully occluded. Defaults to False.
     hide_when_detached: Var[bool]
 
-    _valid_parents: list[str] = ["DropdownMenuSub"]
+    _valid_parents: ClassVar[list[str]] = ["DropdownMenuSub"]
 
     # Fired when the escape key is pressed.
     on_escape_key_down: EventHandler[no_args_event_spec]
@@ -231,7 +231,10 @@ class DropdownMenuItem(RadixThemesComponent):
     # Optional text used for typeahead purposes. By default the typeahead behavior will use the .textContent of the item. Use this when the content is complex, or you have non-textual content inside.
     text_value: Var[str]
 
-    _valid_parents: list[str] = ["DropdownMenuContent", "DropdownMenuSubContent"]
+    _valid_parents: ClassVar[list[str]] = [
+        "DropdownMenuContent",
+        "DropdownMenuSubContent",
+    ]
 
     # Fired when the item is selected.
     on_select: EventHandler[no_args_event_spec]

+ 2 - 2
reflex/components/radix/themes/components/radio_cards.py

@@ -1,7 +1,7 @@
 """Radio component from Radix Themes."""
 
 from types import SimpleNamespace
-from typing import Literal
+from typing import ClassVar, Literal
 
 from reflex.components.core.breakpoints import Responsive
 from reflex.event import EventHandler, passthrough_event_spec
@@ -81,7 +81,7 @@ class RadioCardsItem(RadixThemesComponent):
     # When true, indicates that the user must check the radio item before the owning form can be submitted.
     required: Var[bool]
 
-    _valid_parents: list[str] = ["RadioCardsRoot"]
+    _valid_parents: ClassVar[list[str]] = ["RadioCardsRoot"]
 
 
 class RadioCards(SimpleNamespace):

+ 2 - 2
reflex/components/radix/themes/components/segmented_control.py

@@ -3,7 +3,7 @@
 from __future__ import annotations
 
 from types import SimpleNamespace
-from typing import Literal, Sequence
+from typing import ClassVar, Literal, Sequence
 
 from reflex.components.core.breakpoints import Responsive
 from reflex.event import EventHandler
@@ -66,7 +66,7 @@ class SegmentedControlItem(RadixThemesComponent):
     # The value of the item.
     value: Var[str]
 
-    _valid_parents: list[str] = ["SegmentedControlRoot"]
+    _valid_parents: ClassVar[list[str]] = ["SegmentedControlRoot"]
 
 
 class SegmentedControl(SimpleNamespace):

+ 5 - 5
reflex/components/radix/themes/components/select.py

@@ -1,6 +1,6 @@
 """Interactive components provided by @radix-ui/themes."""
 
-from typing import Literal, Sequence
+from typing import ClassVar, Literal, Sequence
 
 import reflex as rx
 from reflex.components.component import Component, ComponentNamespace
@@ -68,7 +68,7 @@ class SelectTrigger(RadixThemesComponent):
     # The placeholder of the select trigger
     placeholder: Var[str]
 
-    _valid_parents: list[str] = ["SelectRoot"]
+    _valid_parents: ClassVar[list[str]] = ["SelectRoot"]
 
     _memoization_mode = MemoizationMode(recursive=False)
 
@@ -117,7 +117,7 @@ class SelectGroup(RadixThemesComponent):
 
     tag = "Select.Group"
 
-    _valid_parents: list[str] = ["SelectContent"]
+    _valid_parents: ClassVar[list[str]] = ["SelectContent"]
 
 
 class SelectItem(RadixThemesComponent):
@@ -131,7 +131,7 @@ class SelectItem(RadixThemesComponent):
     # Whether the select item is disabled
     disabled: Var[bool]
 
-    _valid_parents: list[str] = ["SelectGroup", "SelectContent"]
+    _valid_parents: ClassVar[list[str]] = ["SelectGroup", "SelectContent"]
 
 
 class SelectLabel(RadixThemesComponent):
@@ -139,7 +139,7 @@ class SelectLabel(RadixThemesComponent):
 
     tag = "Select.Label"
 
-    _valid_parents: list[str] = ["SelectGroup"]
+    _valid_parents: ClassVar[list[str]] = ["SelectGroup"]
 
 
 class SelectSeparator(RadixThemesComponent):

+ 9 - 9
reflex/components/radix/themes/components/table.py

@@ -1,6 +1,6 @@
 """Interactive components provided by @radix-ui/themes."""
 
-from typing import Literal
+from typing import ClassVar, Literal
 
 from reflex.components.component import ComponentNamespace
 from reflex.components.core.breakpoints import Responsive
@@ -27,9 +27,9 @@ class TableHeader(elements.Thead, RadixThemesComponent):
 
     tag = "Table.Header"
 
-    _invalid_children: list[str] = ["TableBody"]
+    _invalid_children: ClassVar[list[str]] = ["TableBody"]
 
-    _valid_parents: list[str] = ["TableRoot"]
+    _valid_parents: ClassVar[list[str]] = ["TableRoot"]
 
 
 class TableRow(elements.Tr, RadixThemesComponent):
@@ -40,7 +40,7 @@ class TableRow(elements.Tr, RadixThemesComponent):
     # The alignment of the row
     align: Var[Literal["start", "center", "end", "baseline"]]
 
-    _invalid_children: list[str] = ["TableBody", "TableHeader", "TableRow"]
+    _invalid_children: ClassVar[list[str]] = ["TableBody", "TableHeader", "TableRow"]
 
 
 class TableColumnHeaderCell(elements.Th, RadixThemesComponent):
@@ -57,7 +57,7 @@ class TableColumnHeaderCell(elements.Th, RadixThemesComponent):
     # The maximum width of the cell
     max_width: Var[Responsive[str]]
 
-    _invalid_children: list[str] = [
+    _invalid_children: ClassVar[list[str]] = [
         "TableBody",
         "TableHeader",
         "TableRow",
@@ -72,14 +72,14 @@ class TableBody(elements.Tbody, RadixThemesComponent):
 
     tag = "Table.Body"
 
-    _invalid_children: list[str] = [
+    _invalid_children: ClassVar[list[str]] = [
         "TableHeader",
         "TableRowHeaderCell",
         "TableColumnHeaderCell",
         "TableCell",
     ]
 
-    _valid_parents: list[str] = ["TableRoot"]
+    _valid_parents: ClassVar[list[str]] = ["TableRoot"]
 
 
 class TableCell(elements.Td, CommonPaddingProps, RadixThemesComponent):
@@ -96,7 +96,7 @@ class TableCell(elements.Td, CommonPaddingProps, RadixThemesComponent):
     # The maximum width of the cell
     max_width: Var[Responsive[str]]
 
-    _invalid_children: list[str] = [
+    _invalid_children: ClassVar[list[str]] = [
         "TableBody",
         "TableHeader",
         "TableRowHeaderCell",
@@ -119,7 +119,7 @@ class TableRowHeaderCell(elements.Th, CommonPaddingProps, RadixThemesComponent):
     # The maximum width of the cell
     max_width: Var[Responsive[str]]
 
-    _invalid_children: list[str] = [
+    _invalid_children: ClassVar[list[str]] = [
         "TableBody",
         "TableHeader",
         "TableRow",

+ 2 - 2
reflex/components/radix/themes/components/tabs.py

@@ -2,7 +2,7 @@
 
 from __future__ import annotations
 
-from typing import Any, Literal
+from typing import Any, ClassVar, Literal
 
 from reflex.components.component import Component, ComponentNamespace
 from reflex.components.core.breakpoints import Responsive
@@ -94,7 +94,7 @@ class TabsTrigger(RadixThemesComponent):
     # The color of the line under the tab when active.
     color_scheme: Var[LiteralAccentColor]
 
-    _valid_parents: list[str] = ["TabsList"]
+    _valid_parents: ClassVar[list[str]] = ["TabsList"]
 
     _memoization_mode = MemoizationMode(recursive=False)
 

+ 2 - 2
reflex/components/radix/themes/layout/flex.py

@@ -2,7 +2,7 @@
 
 from __future__ import annotations
 
-from typing import Literal
+from typing import ClassVar, Literal
 
 from reflex.components.core.breakpoints import Responsive
 from reflex.components.el import elements
@@ -38,7 +38,7 @@ class Flex(elements.Div, RadixThemesComponent):
     spacing: Var[Responsive[LiteralSpacing]]
 
     # Reflex maps the "spacing" prop to "gap" prop.
-    _rename_props: dict[str, str] = {"spacing": "gap"}
+    _rename_props: ClassVar[dict[str, str]] = {"spacing": "gap"}
 
 
 flex = Flex.create

+ 2 - 2
reflex/components/radix/themes/layout/grid.py

@@ -2,7 +2,7 @@
 
 from __future__ import annotations
 
-from typing import Literal
+from typing import ClassVar, Literal
 
 from reflex.components.core.breakpoints import Responsive
 from reflex.components.el import elements
@@ -46,7 +46,7 @@ class Grid(elements.Div, RadixThemesComponent):
     spacing_y: Var[Responsive[LiteralSpacing]]
 
     # Reflex maps the "spacing" prop to "gap" prop.
-    _rename_props: dict[str, str] = {
+    _rename_props: ClassVar[dict[str, str]] = {
         "spacing": "gap",
         "spacing_x": "gap_x",
         "spacing_y": "gap_y",

+ 9 - 9
reflex/components/recharts/cartesian.py

@@ -2,7 +2,7 @@
 
 from __future__ import annotations
 
-from typing import Any, Sequence, Union
+from typing import Any, ClassVar, Sequence, Union
 
 from reflex.constants import EventTriggers
 from reflex.constants.colors import Color
@@ -369,7 +369,7 @@ class Area(Cartesian):
     connect_nulls: Var[bool]
 
     # Valid children components
-    _valid_children: list[str] = ["LabelList"]
+    _valid_children: ClassVar[list[str]] = ["LabelList"]
 
 
 class Bar(Cartesian):
@@ -419,7 +419,7 @@ class Bar(Cartesian):
     # active_bar: Var[Union[bool, dict[str, Any]]] #noqa: ERA001
 
     # Valid children components
-    _valid_children: list[str] = ["Cell", "LabelList", "ErrorBar"]
+    _valid_children: ClassVar[list[str]] = ["Cell", "LabelList", "ErrorBar"]
 
 
 class Line(Cartesian):
@@ -473,7 +473,7 @@ class Line(Cartesian):
     stroke_dasharray: Var[str]
 
     # Valid children components
-    _valid_children: list[str] = ["LabelList", "ErrorBar"]
+    _valid_children: ClassVar[list[str]] = ["LabelList", "ErrorBar"]
 
 
 class Scatter(Recharts):
@@ -514,7 +514,7 @@ class Scatter(Recharts):
     fill: Var[str | Color] = LiteralVar.create(Color("accent", 9))
 
     # Valid children components.
-    _valid_children: list[str] = ["LabelList", "ErrorBar"]
+    _valid_children: ClassVar[list[str]] = ["LabelList", "ErrorBar"]
 
     # If set false, animation of bar will be disabled. Default: True in CSR, False in SSR
     is_animation_active: Var[bool]
@@ -591,7 +591,7 @@ class Funnel(Recharts):
     trapezoids: Var[Sequence[dict[str, Any]]]
 
     # Valid children components
-    _valid_children: list[str] = ["LabelList", "Cell"]
+    _valid_children: ClassVar[list[str]] = ["LabelList", "Cell"]
 
     # The customized event handler of animation start
     on_animation_start: EventHandler[no_args_event_spec]
@@ -686,7 +686,7 @@ class ReferenceLine(Reference):
     stroke_width: Var[str | int]
 
     # Valid children components
-    _valid_children: list[str] = ["Label"]
+    _valid_children: ClassVar[list[str]] = ["Label"]
 
     # Array of endpoints in { x, y } format. These endpoints would be used to draw the ReferenceLine.
     segment: Sequence[Any] = []
@@ -715,7 +715,7 @@ class ReferenceDot(Reference):
     stroke: Var[str | Color]
 
     # Valid children components
-    _valid_children: list[str] = ["Label"]
+    _valid_children: ClassVar[list[str]] = ["Label"]
 
     # The customized event handler of click on the component in this chart
     on_click: EventHandler[no_args_event_spec]
@@ -783,7 +783,7 @@ class ReferenceArea(Recharts):
     is_front: Var[bool]
 
     # Valid children components
-    _valid_children: list[str] = ["Label"]
+    _valid_children: ClassVar[list[str]] = ["Label"]
 
 
 class Grid(Recharts):

+ 10 - 10
reflex/components/recharts/charts.py

@@ -2,7 +2,7 @@
 
 from __future__ import annotations
 
-from typing import Any, Sequence
+from typing import Any, ClassVar, Sequence
 
 from reflex.components.component import Component
 from reflex.components.recharts.general import ResponsiveContainer
@@ -133,7 +133,7 @@ class AreaChart(CategoricalChartBase):
     base_value: Var[int | LiteralComposedChartBaseValue]
 
     # Valid children components
-    _valid_children: list[str] = [
+    _valid_children: ClassVar[list[str]] = [
         "XAxis",
         "YAxis",
         "ReferenceArea",
@@ -174,7 +174,7 @@ class BarChart(CategoricalChartBase):
     reverse_stack_order: Var[bool]
 
     # Valid children components
-    _valid_children: list[str] = [
+    _valid_children: ClassVar[list[str]] = [
         "XAxis",
         "YAxis",
         "ReferenceArea",
@@ -196,7 +196,7 @@ class LineChart(CategoricalChartBase):
     alias = "RechartsLineChart"
 
     # Valid children components
-    _valid_children: list[str] = [
+    _valid_children: ClassVar[list[str]] = [
         "XAxis",
         "YAxis",
         "ReferenceArea",
@@ -233,7 +233,7 @@ class ComposedChart(CategoricalChartBase):
     reverse_stack_order: Var[bool]
 
     # Valid children components
-    _valid_children: list[str] = [
+    _valid_children: ClassVar[list[str]] = [
         "XAxis",
         "YAxis",
         "ReferenceArea",
@@ -260,7 +260,7 @@ class PieChart(ChartBase):
     margin: Var[dict[str, Any]]
 
     # Valid children components
-    _valid_children: list[str] = [
+    _valid_children: ClassVar[list[str]] = [
         "PolarAngleAxis",
         "PolarRadiusAxis",
         "PolarGrid",
@@ -314,7 +314,7 @@ class RadarChart(ChartBase):
     outer_radius: Var[int | str]
 
     # Valid children components
-    _valid_children: list[str] = [
+    _valid_children: ClassVar[list[str]] = [
         "PolarAngleAxis",
         "PolarRadiusAxis",
         "PolarGrid",
@@ -377,7 +377,7 @@ class RadialBarChart(ChartBase):
     bar_size: Var[int]
 
     # Valid children components
-    _valid_children: list[str] = [
+    _valid_children: ClassVar[list[str]] = [
         "PolarAngleAxis",
         "PolarRadiusAxis",
         "PolarGrid",
@@ -398,7 +398,7 @@ class ScatterChart(ChartBase):
     margin: Var[dict[str, Any]]
 
     # Valid children components
-    _valid_children: list[str] = [
+    _valid_children: ClassVar[list[str]] = [
         "XAxis",
         "YAxis",
         "ZAxis",
@@ -447,7 +447,7 @@ class FunnelChart(ChartBase):
     stroke: Var[str | Color]
 
     # Valid children components
-    _valid_children: list[str] = ["Legend", "GraphingTooltip", "Funnel"]
+    _valid_children: ClassVar[list[str]] = ["Legend", "GraphingTooltip", "Funnel"]
 
 
 class Treemap(RechartsCharts):

+ 2 - 2
reflex/components/recharts/general.py

@@ -2,7 +2,7 @@
 
 from __future__ import annotations
 
-from typing import Any, Sequence, Union
+from typing import Any, ClassVar, Sequence, Union
 
 from reflex.components.component import MemoizationLeaf
 from reflex.constants.colors import Color
@@ -49,7 +49,7 @@ class ResponsiveContainer(Recharts, MemoizationLeaf):
     on_resize: EventHandler[no_args_event_spec]
 
     # Valid children components
-    _valid_children: list[str] = [
+    _valid_children: ClassVar[list[str]] = [
         "AreaChart",
         "BarChart",
         "LineChart",

+ 7 - 7
reflex/components/recharts/polar.py

@@ -2,7 +2,7 @@
 
 from __future__ import annotations
 
-from typing import Any, Sequence, Union
+from typing import Any, ClassVar, Sequence, Union
 
 from reflex.constants import EventTriggers
 from reflex.constants.colors import Color
@@ -70,7 +70,7 @@ class Pie(Recharts):
     label_line: Var[bool]
 
     # Valid children components
-    _valid_children: list[str] = ["Cell", "LabelList", "Bare"]
+    _valid_children: ClassVar[list[str]] = ["Cell", "LabelList", "Bare"]
 
     # Stoke color. Default: rx.color("accent", 9)
     stroke: Var[str | Color] = LiteralVar.create(Color("accent", 9))
@@ -155,7 +155,7 @@ class Radar(Recharts):
     animation_easing: Var[LiteralAnimationEasing]
 
     # Valid children components
-    _valid_children: list[str] = ["LabelList"]
+    _valid_children: ClassVar[list[str]] = ["LabelList"]
 
     def get_event_triggers(self) -> dict[str, Var | Any]:
         """Get the event triggers that pass the component's value to the handler.
@@ -207,7 +207,7 @@ class RadialBar(Recharts):
     animation_easing: Var[LiteralAnimationEasing]
 
     # Valid children components
-    _valid_children: list[str] = ["Cell", "LabelList"]
+    _valid_children: ClassVar[list[str]] = ["Cell", "LabelList"]
 
     def get_event_triggers(self) -> dict[str, Var | Any]:
         """Get the event triggers that pass the component's value to the handler.
@@ -271,7 +271,7 @@ class PolarAngleAxis(Recharts):
     allow_duplicated_category: Var[bool]
 
     # Valid children components.
-    _valid_children: list[str] = ["Label"]
+    _valid_children: ClassVar[list[str]] = ["Label"]
 
     # The customized event handler of click on the ticks of this axis.
     on_click: EventHandler[no_args_event_spec]
@@ -330,7 +330,7 @@ class PolarGrid(Recharts):
     stroke: Var[str | Color] = LiteralVar.create(Color("gray", 10))
 
     # Valid children components
-    _valid_children: list[str] = ["RadarChart", "RadiarBarChart"]
+    _valid_children: ClassVar[list[str]] = ["RadarChart", "RadiarBarChart"]
 
 
 class PolarRadiusAxis(Recharts):
@@ -374,7 +374,7 @@ class PolarRadiusAxis(Recharts):
     scale: Var[LiteralScale]
 
     # Valid children components
-    _valid_children: list[str] = ["Label"]
+    _valid_children: ClassVar[list[str]] = ["Label"]
 
     # The domain of the polar radius axis, specifying the minimum and maximum values. Default: [0, "auto"]
     domain: Var[Sequence[int | str]]

+ 7 - 1
reflex/style.py

@@ -234,6 +234,9 @@ def format_style_key(key: str) -> tuple[str, ...]:
     return STYLE_PROP_SHORTHAND_MAPPING.get(key, (key,))
 
 
+EMPTY_VAR_DATA = VarData()
+
+
 class Style(dict):
     """A style dictionary."""
 
@@ -248,7 +251,10 @@ class Style(dict):
             style_dict.update(kwargs)
         else:
             style_dict = kwargs
-        style_dict, self._var_data = convert(style_dict or {})
+        if style_dict:
+            style_dict, self._var_data = convert(style_dict)
+        else:
+            self._var_data = EMPTY_VAR_DATA
         super().__init__(style_dict)
 
     def update(self, style_dict: dict | None, **kwargs):

+ 6 - 0
reflex/utils/pyi_generator.py

@@ -886,6 +886,12 @@ class StubGenerator(ast.NodeTransformer):
         call_definition = None
         for child in node.body[:]:
             found_call = False
+            if (
+                isinstance(child, ast.AnnAssign)
+                and isinstance(child.target, ast.Name)
+                and child.target.id.startswith("_")
+            ):
+                node.body.remove(child)
             if isinstance(child, ast.Assign):
                 for target in child.targets[:]:
                     if isinstance(target, ast.Name) and target.id == "__call__":

+ 2 - 2
tests/units/components/core/test_banner.py

@@ -25,7 +25,7 @@ def test_connection_banner():
             "react",
             "$/utils/context",
             "$/utils/state",
-            RadixThemesComponent().library or "",
+            RadixThemesComponent.create().library or "",
             "$/env.json",
         )
     )
@@ -43,7 +43,7 @@ def test_connection_modal():
             "react",
             "$/utils/context",
             "$/utils/state",
-            RadixThemesComponent().library or "",
+            RadixThemesComponent.create().library or "",
             "$/env.json",
         )
     )

+ 3 - 3
tests/units/components/core/test_cond.py

@@ -49,7 +49,7 @@ def test_validate_cond(cond_state: BaseState):
     assert cond_dict["name"] == "Fragment"
 
     [condition] = cond_dict["children"]
-    assert condition["cond_state"] == f"isTrue({cond_state.get_full_name()}.value)"
+    assert condition["cond_state"] == str(cond_state.value.bool())
 
     # true value
     true_value = condition["true_value"]
@@ -113,8 +113,8 @@ def test_cond_no_else():
     comp = comp.children[0]
     assert isinstance(comp, Cond)
     assert comp.cond._decode() is True
-    assert comp.comp1.render() == Fragment.create(Text.create("hello")).render()  # pyright: ignore [reportOptionalMemberAccess]
-    assert comp.comp2 == Fragment.create()
+    assert comp.children[0].render() == Fragment.create(Text.create("hello")).render()  # pyright: ignore [reportOptionalMemberAccess]
+    assert comp.children[1] == Fragment.create()
 
     # Props do not support the use of cond without else
     with pytest.raises(ValueError):

+ 1 - 1
tests/units/components/core/test_debounce.py

@@ -118,7 +118,7 @@ def test_event_triggers():
         )
     )
     assert tuple(debounced_input.get_event_triggers()) == (
-        *rx.Component().get_event_triggers(),  # default event triggers
+        *rx.Component.create().get_event_triggers(),  # default event triggers
         "on_change",
     )
 

+ 47 - 40
tests/units/components/test_component.py

@@ -1,5 +1,5 @@
 from contextlib import nullcontext
-from typing import Any, Type, Union
+from typing import Any, ClassVar, Type, Union
 
 import pytest
 
@@ -179,11 +179,11 @@ def component5() -> Type[Component]:
     class TestComponent5(Component):
         tag = "RandomComponent"
 
-        _invalid_children: list[str] = ["Text"]
+        _invalid_children: ClassVar[list[str]] = ["Text"]
 
-        _valid_children: list[str] = ["Text"]
+        _valid_children: ClassVar[list[str]] = ["Text"]
 
-        _valid_parents: list[str] = ["Text"]
+        _valid_parents: ClassVar[list[str]] = ["Text"]
 
     return TestComponent5
 
@@ -199,7 +199,7 @@ def component6() -> Type[Component]:
     class TestComponent6(Component):
         tag = "RandomComponent"
 
-        _invalid_children: list[str] = ["Text"]
+        _invalid_children: ClassVar[list[str]] = ["Text"]
 
     return TestComponent6
 
@@ -215,7 +215,7 @@ def component7() -> Type[Component]:
     class TestComponent7(Component):
         tag = "RandomComponent"
 
-        _valid_children: list[str] = ["Text"]
+        _valid_children: ClassVar[list[str]] = ["Text"]
 
     return TestComponent7
 
@@ -279,7 +279,7 @@ def test_custom_attrs(component1):
     Args:
         component1: A test component.
     """
-    component = component1(custom_attrs={"attr1": "1", "attr2": "attr2"})
+    component = component1.create(custom_attrs={"attr1": "1", "attr2": "attr2"})
     assert component.custom_attrs == {"attr1": "1", "attr2": "attr2"}
 
 
@@ -289,7 +289,7 @@ def test_create_component(component1):
     Args:
         component1: A test component.
     """
-    children = [component1() for _ in range(3)]
+    children = [component1.create() for _ in range(3)]
     attrs = {"color": "white", "text_align": "center"}
     c = component1.create(*children, **attrs)
     assert isinstance(c, component1)
@@ -459,8 +459,8 @@ def test_add_style(component1, component2):
         component1: Style({"color": "white"}),
         component2: Style({"color": "black"}),
     }
-    c1 = component1()._add_style_recursive(style)
-    c2 = component2()._add_style_recursive(style)
+    c1 = component1.create()._add_style_recursive(style)
+    c2 = component2.create()._add_style_recursive(style)
     assert str(c1.style["color"]) == '"white"'
     assert str(c2.style["color"]) == '"black"'
 
@@ -476,8 +476,8 @@ def test_add_style_create(component1, component2):
         component1.create: Style({"color": "white"}),
         component2.create: Style({"color": "black"}),
     }
-    c1 = component1()._add_style_recursive(style)
-    c2 = component2()._add_style_recursive(style)
+    c1 = component1.create()._add_style_recursive(style)
+    c2 = component2.create()._add_style_recursive(style)
     assert str(c1.style["color"]) == '"white"'
     assert str(c2.style["color"]) == '"black"'
 
@@ -609,9 +609,9 @@ def test_get_event_triggers(component1, component2):
         EventTriggers.ON_MOUNT,
         EventTriggers.ON_UNMOUNT,
     }
-    assert component1().get_event_triggers().keys() == default_triggers
+    assert component1.create().get_event_triggers().keys() == default_triggers
     assert (
-        component2().get_event_triggers().keys()
+        component2.create().get_event_triggers().keys()
         == {
             "on_open",
             "on_close",
@@ -640,8 +640,8 @@ def test_component() -> Type[Component]:
 
 # Write a test case to check if the create method filters out None props
 def test_create_filters_none_props(test_component):
-    child1 = test_component()
-    child2 = test_component()
+    child1 = test_component.create()
+    child2 = test_component.create()
     props = {
         "prop1": "value1",
         "prop2": None,
@@ -1082,7 +1082,7 @@ def test_get_hooks_nested(component1, component2, component3):
         text="a",
         number=1,
     )
-    assert c._get_all_hooks() == component3()._get_all_hooks()
+    assert c._get_all_hooks() == component3.create()._get_all_hooks()
 
 
 def test_get_hooks_nested2(component3, component4):
@@ -1092,7 +1092,10 @@ def test_get_hooks_nested2(component3, component4):
         component3: component with hooks defined.
         component4: component with different hooks defined.
     """
-    exp_hooks = {**component3()._get_all_hooks(), **component4()._get_all_hooks()}
+    exp_hooks = {
+        **component3.create()._get_all_hooks(),
+        **component4.create()._get_all_hooks(),
+    }
     assert component3.create(component4.create())._get_all_hooks() == exp_hooks
     assert component4.create(component3.create())._get_all_hooks() == exp_hooks
     assert (
@@ -1955,29 +1958,29 @@ def test_component_add_hooks():
                 "const hook6 = 47",
             ]
 
-    assert list(BaseComponent()._get_all_hooks()) == ["const hook1 = 42"]
-    assert list(ChildComponent1()._get_all_hooks()) == ["const hook1 = 42"]
-    assert list(GrandchildComponent1()._get_all_hooks()) == [
+    assert list(BaseComponent.create()._get_all_hooks()) == ["const hook1 = 42"]
+    assert list(ChildComponent1.create()._get_all_hooks()) == ["const hook1 = 42"]
+    assert list(GrandchildComponent1.create()._get_all_hooks()) == [
         "const hook1 = 42",
         "const hook2 = 43",
         "const hook3 = 44",
     ]
-    assert list(GreatGrandchildComponent1()._get_all_hooks()) == [
+    assert list(GreatGrandchildComponent1.create()._get_all_hooks()) == [
         "const hook1 = 42",
         "const hook2 = 43",
         "const hook3 = 44",
         "const hook4 = 45",
     ]
-    assert list(GrandchildComponent2()._get_all_hooks()) == ["const hook5 = 46"]
-    assert list(GreatGrandchildComponent2()._get_all_hooks()) == [
+    assert list(GrandchildComponent2.create()._get_all_hooks()) == ["const hook5 = 46"]
+    assert list(GreatGrandchildComponent2.create()._get_all_hooks()) == [
         "const hook5 = 46",
         "const hook2 = 43",
         "const hook6 = 47",
     ]
     assert list(
         BaseComponent.create(
-            GrandchildComponent1.create(GreatGrandchildComponent2()),
-            GreatGrandchildComponent1(),
+            GrandchildComponent1.create(GreatGrandchildComponent2.create()),
+            GreatGrandchildComponent1.create(),
         )._get_all_hooks(),
     ) == [
         "const hook1 = 42",
@@ -1989,8 +1992,8 @@ def test_component_add_hooks():
     ]
     assert list(
         Fragment.create(
-            GreatGrandchildComponent2(),
-            GreatGrandchildComponent1(),
+            GreatGrandchildComponent2.create(),
+            GreatGrandchildComponent1.create(),
         )._get_all_hooks()
     ) == [
         "const hook5 = 46",
@@ -2034,28 +2037,32 @@ def test_component_add_custom_code():
                 "const custom_code6 = 47",
             ]
 
-    assert BaseComponent()._get_all_custom_code() == {"const custom_code1 = 42"}
-    assert ChildComponent1()._get_all_custom_code() == {"const custom_code1 = 42"}
-    assert GrandchildComponent1()._get_all_custom_code() == {
+    assert BaseComponent.create()._get_all_custom_code() == {"const custom_code1 = 42"}
+    assert ChildComponent1.create()._get_all_custom_code() == {
+        "const custom_code1 = 42"
+    }
+    assert GrandchildComponent1.create()._get_all_custom_code() == {
         "const custom_code1 = 42",
         "const custom_code2 = 43",
         "const custom_code3 = 44",
     }
-    assert GreatGrandchildComponent1()._get_all_custom_code() == {
+    assert GreatGrandchildComponent1.create()._get_all_custom_code() == {
         "const custom_code1 = 42",
         "const custom_code2 = 43",
         "const custom_code3 = 44",
         "const custom_code4 = 45",
     }
-    assert GrandchildComponent2()._get_all_custom_code() == {"const custom_code5 = 46"}
-    assert GreatGrandchildComponent2()._get_all_custom_code() == {
+    assert GrandchildComponent2.create()._get_all_custom_code() == {
+        "const custom_code5 = 46"
+    }
+    assert GreatGrandchildComponent2.create()._get_all_custom_code() == {
         "const custom_code2 = 43",
         "const custom_code5 = 46",
         "const custom_code6 = 47",
     }
     assert BaseComponent.create(
-        GrandchildComponent1.create(GreatGrandchildComponent2()),
-        GreatGrandchildComponent1(),
+        GrandchildComponent1.create(GreatGrandchildComponent2.create()),
+        GreatGrandchildComponent1.create(),
     )._get_all_custom_code() == {
         "const custom_code1 = 42",
         "const custom_code2 = 43",
@@ -2065,8 +2072,8 @@ def test_component_add_custom_code():
         "const custom_code6 = 47",
     }
     assert Fragment.create(
-        GreatGrandchildComponent2(),
-        GreatGrandchildComponent1(),
+        GreatGrandchildComponent2.create(),
+        GreatGrandchildComponent1.create(),
     )._get_all_custom_code() == {
         "const custom_code1 = 42",
         "const custom_code2 = 43",
@@ -2099,13 +2106,13 @@ def test_component_add_hooks_var():
                 ),
             ]
 
-    assert list(HookComponent()._get_all_hooks()) == [
+    assert list(HookComponent.create()._get_all_hooks()) == [
         "const hook3 = useRef(null)",
         "const hook1 = 42",
         "const hook2 = 43",
         "useEffect(() => () => {}, [])",
     ]
-    imports = HookComponent()._get_all_imports()
+    imports = HookComponent.create()._get_all_imports()
     assert len(imports) == 1
     assert "react" in imports
     assert len(imports["react"]) == 2