diff --git a/reflex/components/component.py b/reflex/components/component.py index f0e85f249..f777d1a63 100644 --- a/reflex/components/component.py +++ b/reflex/components/component.py @@ -358,9 +358,12 @@ class Component(Base, ABC): return _compile_component(self) - def _render(self) -> Tag: + def _render(self, props: dict[str, Any] | None = None) -> Tag: """Define how to render the component in React. + Args: + props: The props to render (if None, then use get_props). + Returns: The tag to render. """ @@ -370,16 +373,26 @@ class Component(Base, ABC): special_props=self.special_props, ) - # Add component props to the tag. - props = { - attr[:-1] if attr.endswith("_") else attr: getattr(self, attr) - for attr in self.get_props() - } + if props is None: + # Add component props to the tag. + props = { + attr[:-1] if attr.endswith("_") else attr: getattr(self, attr) + for attr in self.get_props() + } - # Add ref to element if `id` is not None. - ref = self.get_ref() - if ref is not None: - props["ref"] = Var.create(ref, _var_is_local=False) + # Add ref to element if `id` is not None. + ref = self.get_ref() + if ref is not None: + props["ref"] = Var.create(ref, _var_is_local=False) + + props.update( + self.event_triggers, + key=self.key, + id=self.id, + class_name=self.class_name, + ) + props.update(self._get_style()) + props.update(self.custom_attrs) return tag.add_props(**props) @@ -501,14 +514,7 @@ class Component(Base, ABC): """ tag = self._render() rendered_dict = dict( - tag.add_props( - **self.event_triggers, - key=self.key, - id=self.id, - class_name=self.class_name, - **self._get_style(), - **self.custom_attrs, - ).set( + tag.set( children=[child.render() for child in self.children], contents=str(tag.contents), props=tag.format_props(), @@ -949,10 +955,7 @@ class CustomComponent(Component): Returns: The tag to render. """ - return Tag( - name=self.tag if not self.alias else self.alias, - special_props=self.special_props, - ).add_props(**self.props) + return super()._render(props=self.props) def get_prop_vars(self) -> List[BaseVar]: """Get the prop vars. diff --git a/reflex/components/forms/form.py b/reflex/components/forms/form.py index 13d6f042d..ee793da2f 100644 --- a/reflex/components/forms/form.py +++ b/reflex/components/forms/form.py @@ -11,7 +11,7 @@ from reflex.components.tags import Tag from reflex.constants import EventTriggers from reflex.event import EventChain from reflex.utils import imports -from reflex.utils.format import format_event_chain +from reflex.utils.format import format_event_chain, to_camel_case from reflex.utils.serializers import serialize from reflex.vars import BaseVar, Var, get_unique_variable_name @@ -82,23 +82,25 @@ class Form(ChakraComponent): ) def _render(self) -> Tag: - return ( + render_tag = ( super() ._render() - .remove_props("reset_on_submit", "handle_submit_unique_name") + .remove_props( + "reset_on_submit", + "handle_submit_unique_name", + to_camel_case(EventTriggers.ON_SUBMIT), + ) ) - - def render(self) -> dict: - """Render the component. - - Returns: - The rendered component. - """ - self.event_triggers[EventTriggers.ON_SUBMIT] = BaseVar( - _var_name=f"handleSubmit{self.handle_submit_unique_name}", - _var_type=EventChain, - ) - return super().render() + if EventTriggers.ON_SUBMIT in self.event_triggers: + render_tag.add_props( + **{ + EventTriggers.ON_SUBMIT: BaseVar( + _var_name=f"handleSubmit{self.handle_submit_unique_name}", + _var_type=EventChain, + ) + } + ) + return render_tag def _get_form_refs(self) -> Dict[str, Any]: # Send all the input refs to the handler. diff --git a/tests/components/forms/test_form.py b/tests/components/forms/test_form.py new file mode 100644 index 000000000..d57b6f95c --- /dev/null +++ b/tests/components/forms/test_form.py @@ -0,0 +1,21 @@ +from reflex.components.forms.form import Form +from reflex.event import EventChain +from reflex.vars import BaseVar + + +def test_render_on_submit(): + """Test that on_submit event chain is rendered as a separate function.""" + submit_it = BaseVar( + _var_name="submit_it", + _var_type=EventChain, + ) + f = Form.create(on_submit=submit_it) + exp_submit_name = f"handleSubmit{f.handle_submit_unique_name}" # type: ignore + assert f"onSubmit={{{exp_submit_name}}}" in f.render()["props"] + + +def test_render_no_on_submit(): + """A form without on_submit should not render a submit handler.""" + f = Form.create() + for prop in f.render()["props"]: + assert "onSubmit" not in prop