@@ -75,6 +75,18 @@ class LeafComponent(Component):
7575 _memoization_mode = MemoizationMode (recursive = False )
7676
7777
78+ class ChildrenViaProp (Component ):
79+ """Stub mirroring ``CodeBlock`` — injects its content as ``children`` prop."""
80+
81+ tag = "ChildrenViaProp"
82+ library = "children-via-prop-lib"
83+
84+ code : Var [str ] = component_field (default = LiteralVar .create ("" ))
85+
86+ def _render (self ):
87+ return super ()._render ().remove_props ("code" ).add_props (children = self .code )
88+
89+
7890class SpecialFormMemoState (BaseState ):
7991 items : Field [list [str ]] = field (default_factory = lambda : ["a" ])
8092 flag : Field [bool ] = field (default = True )
@@ -417,6 +429,23 @@ def test_generated_memo_component_is_not_itself_memoized() -> None:
417429 assert not _should_memoize (wrapper )
418430
419431
432+ def test_passthrough_memo_skips_hole_for_childless_component () -> None :
433+ """Childless components own their JSX output, so the wrapper must not
434+ inject a ``{children}`` hole.
435+
436+ Regression: components like ``CodeBlock`` set ``children`` on their own
437+ rendered Tag via ``_render``. Substituting a ``Bare({children})`` hole
438+ would emit ``jsx(Inner, {children: "..."}, hole)``, and at call time the
439+ undefined hole arg overwrites ``props.children`` under Emotion's jsx
440+ semantics — causing every reactive ``rx.code_block`` to render an empty
441+ ``<code>`` element.
442+ """
443+ component = ChildrenViaProp .create (code = STATE_VAR )
444+ assert not component .children
445+ _wrapper_factory , definition = create_passthrough_component_memo (component )
446+ assert definition .passthrough_hole_child is None
447+
448+
420449def test_event_trigger_memoization_not_emit_usecallback_in_page_hooks () -> None :
421450 """Components with event triggers do not get useCallback wrappers at the page level."""
422451 from reflex_base .event import EventChain
0 commit comments