Skip to content

fix(memo): skip {children} hole substitution when wrapped component h…#6466

Merged
carlosabadia merged 2 commits intomainfrom
carlos/fix-docs-intro-demo
May 7, 2026
Merged

fix(memo): skip {children} hole substitution when wrapped component h…#6466
carlosabadia merged 2 commits intomainfrom
carlos/fix-docs-intro-demo

Conversation

@carlosabadia
Copy link
Copy Markdown
Contributor

…as no structural children

@carlosabadia carlosabadia requested a review from a team as a code owner May 7, 2026 08:43
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 7, 2026

Greptile Summary

This PR fixes a JSX prop clobbering bug in the auto-memoization pipeline for components that own their own children prop in _render (e.g. CodeBlock) but carry an empty Python-level children list. The {children} hole substitution was unconditionally applied, emitting jsx(Inner, {children: \"...\"}, hole) where the undefined hole at call time would overwrite the prop.

  • Root cause & fix: A single guard if not component.children: return new_component is added inside the passthrough closure so that structurally childless components skip hole substitution entirely. The wrapper's children parameter remains in the generated JS signature but is intentionally unused.
  • Downstream safety: passthrough_hole_child defaults to None, and compile_experimental_component_memo already has a hole_child is not None branch that falls back to a full deepcopy+render path, so the None case is handled correctly with no new code required in the compiler.

Confidence Score: 4/5

Safe to merge; the change is a one-guard early return that restores correct JSX output for components like CodeBlock without touching any other code path.

The fix is surgical and the passthrough_hole_child = None fallback in the compiler was already present, so no downstream breakage is expected. The only gap is the absence of a dedicated regression test specifically exercising the new not component.children path — meaning a future refactor could silently reintroduce the bug without a failing test to catch it.

reflex/experimental/memo.py — the new guard is straightforward, but tests/units/compiler/test_memoize_plugin.py has no test covering the new early-return branch.

Important Files Changed

Filename Overview
reflex/experimental/memo.py Adds an early-return guard in the passthrough closure of create_passthrough_component_memo to skip {children} hole substitution for components whose Python-level children list is empty, preventing JSX prop clobbering for components like CodeBlock that inject children internally via _render.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["create_passthrough_component_memo(component)"] --> B["new_component = copy(component)"]
    B --> C{render_snapshot?}
    C -- yes --> D["return new_component\n(snapshot mode)"]
    C -- no --> E{"component.children\nempty? (NEW GUARD)"}
    E -- yes --> F["return new_component\n(no hole substitution)\npassthrough_hole_child = None"]
    E -- no --> G["hole_bare = Bare.create(children)\nnew_component.children = [hole_bare]\ndelegate _get_all_refs"]
    G --> H["return new_component\npassthrough_hole_child = hole_bare"]
    F --> I["compile_experimental_component_memo"]
    H --> I
    I --> J{hole_child is not None?}
    J -- yes --> K["Shallow copy + hole swap\nrender with {children} placeholder"]
    J -- no --> L["deepcopy + full render\n(no hole, component owns its JSX)"]
Loading

Reviews (1): Last reviewed commit: "fix(memo): skip {children} hole substitu..." | Re-trigger Greptile

Comment thread reflex/experimental/memo.py
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented May 7, 2026

Merging this PR will not alter performance

✅ 24 untouched benchmarks
⏩ 2 skipped benchmarks1


Comparing carlos/fix-docs-intro-demo (82d9c4f) with main (1ffc3b5)

Open in CodSpeed

Footnotes

  1. 2 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@carlosabadia carlosabadia merged commit 373d98a into main May 7, 2026
68 of 69 checks passed
@carlosabadia carlosabadia deleted the carlos/fix-docs-intro-demo branch May 7, 2026 13:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants