fix(Html): prevent React root recreation memory leak #2565
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Why
Resolves #2499
The
<Html>component was experiencing severe memory leaks where DOM nodes and event listeners accumulated continuously during normal usage. Two critical issues were identified:The effect with dependencies
[target, transform]would executeroot.current = ReactDOM.createRoot(el)repeatedly, orphaning old roots that were never unmounted. Additionally, when components unmounted due to visibility changes, the DOM element was removed before the React root was unmounted, preventing proper event listener cleanup.Lifecycle before fix:
What
Implemented five fixes to prevent React root recreation and ensure proper cleanup:
1. Conditional Root Creation (Line 212)
Only create the root once when it doesn't exist, then reuse it for the component's lifetime.
2. Cleanup Ordering in DOM Effect (Lines 227-235)
Ensures React root is unmounted before DOM removal, allowing event listeners to detach properly. This cleanup runs when
targetortransformdependencies change (common during visibility toggling).3. Dedicated Cleanup Effect (Lines 241-246)
Empty dependency array ensures cleanup runs on final component unmount. Provides defense-in-depth: root is unmounted both on dependency changes (fix #2) and on final unmount (this fix).
4. Add Dependency Array to Render Effect (Line 293)
Prevents the render effect from running on every frame. Only re-renders when props actually change.
5. Add Missing Dependency (Line 208)
Added missing
zIndexRangedependency to canvas style effect to prevent stale closures.Verification:
Tested with Chrome DevTools Performance Monitor and custom event listener instrumentation for over 1 hour of continuous usage (repeated spinning globe label show/hide and position changes).
Before fix:
After fix:
Checklist
This is a pure bug fix with no API changes or breaking changes. No documentation or storybook updates are required.