Skip to content

Conversation

@kiwina
Copy link
Contributor

@kiwina kiwina commented Jun 2, 2025

PR Type

  • Bugfix

Description

This PR addresses multiple potential memory leaks in the CodeBlock component located at webview-ui/src/components/common/CodeBlock.tsx related to unmanaged asynchronous operations and setTimeout calls.

Specifically, it resolves issues where:

  1. The useEffect hook for syntax highlighting (original line 247) could call setHighlightedCode on an unmounted component.
  2. A useEffect hook (original line 456) using setTimeout (original line 459) to update button positions did not clear the timeout on unmount or re-render.
  3. Nested setTimeout calls in the collapse/expand button's onClick handler (original lines 694, 699) were not cleared on unmount.

The fix implements the following patterns:

  1. An isMountedRef is used to track the component's mounted state, preventing state updates on unmounted components for async operations.
  2. setTimeout IDs are stored in refs (buttonPositionTimeoutRef, collapseTimeout1Ref, collapseTimeout2Ref).
  3. Timeouts are cleared before new ones are set and in useEffect cleanup functions to ensure they don't execute after the component unmounts.
  4. Checks for codeBlockRef.current are added before DOM manipulations within timeout callbacks.

These changes ensure that state updates are not attempted on unmounted components and that timeouts are properly managed, resolving potential memory leaks and eliminating associated React warnings.

Related Issue

#4243

Changes

  • Modified webview-ui/src/components/common/CodeBlock.tsx to include mounted state checks and proper cleanup for asynchronous operations and setTimeout calls.

Testing

Manual testing:

  1. Introduce delays in getHighlighter, codeToHtml, or within setTimeout callbacks to simulate longer async operations.
  2. Render a CodeBlock component.
  3. Quickly unmount the CodeBlock component (e.g., by removing its parent, navigating away, or rapidly clicking the collapse/expand button).
  4. Observe the console for "Can't perform a React state update on an unmounted component" warnings. With the fix, this warning should no longer appear.

Important

Fixes memory leaks in CodeBlock component by managing async operations and setTimeout calls with proper cleanup and mount state checks.

  • Behavior:
    • Fixes memory leaks in CodeBlock component by managing async operations and setTimeout calls.
    • Uses isMountedRef to prevent state updates on unmounted components.
    • Clears setTimeout IDs stored in refs (buttonPositionTimeoutRef, collapseTimeout1Ref, collapseTimeout2Ref) on unmount.
    • Adds checks for codeBlockRef.current before DOM manipulations in timeout callbacks.
  • Code Changes:
    • Modifies useEffect hooks to include cleanup functions for timeouts.
    • Updates highlight() function to check isMountedRef before setting state.
    • Adjusts onClick handler for collapse/expand button to clear nested timeouts.
  • Testing:
    • Manual testing involves simulating async delays and unmounting CodeBlock to check for React warnings.

This description was created by Ellipsis for 4313d4c. You can customize this summary. It will automatically update as commits are pushed.

@kiwina kiwina requested review from cte and mrubens as code owners June 2, 2025 07:53
@dosubot dosubot bot added size:M This PR changes 30-99 lines, ignoring generated files. bug Something isn't working labels Jun 2, 2025
@daniel-lxs daniel-lxs moved this from Triage to PR [Needs Prelim Review] in Roo Code Roadmap Jun 2, 2025
Copy link
Member

@daniel-lxs daniel-lxs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @kiwina, Thank you for your contribution,

I left a couple of comments about code organization, nothing major.

Thank you for taking the time to cleanup the memory leaks, let me know what you think!

return () => {
isMountedRef.current = false
}
}, [])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a specific reason for having a dedicated useEffect just for managing isMountedRef? This could potentially be integrated into the existing syntax highlighting effect since they have the same lifecycle. Just curious about the design choice here!

clearTimeout(collapseTimeout2Ref.current)
}
}
}, [])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that the cleanup pattern for timeouts is a bit inconsistent. The buttonPositionTimeoutRef is cleaned up in the same effect that sets it (lines 521-526), while the collapse timeouts have a separate cleanup effect here.

Could we consider consolidating these patterns? Having a consistent approach would improve maintainability. What do you think about either:

  1. Moving all timeout cleanups to their respective effects, or
  2. Having a single cleanup effect for all timeouts?

Both approaches would work, just wondering if there's a preference!

@daniel-lxs daniel-lxs moved this from PR [Needs Prelim Review] to PR [Changes Requested] in Roo Code Roadmap Jun 6, 2025
- Consolidate isMountedRef management into syntax highlighting useEffect
- Unify timeout cleanup patterns for consistent maintainability
- Maintain all existing memory leak protections
- Improve code organization and readability

Addresses review comments from daniel-lxs in PR RooCodeInc#4244
@daniel-lxs daniel-lxs requested a review from jr as a code owner June 23, 2025 22:27
Copy link
Member

@daniel-lxs daniel-lxs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied the requested changes.

LGTM

@dosubot dosubot bot added the lgtm This PR has been approved by a maintainer label Jun 23, 2025
@daniel-lxs daniel-lxs moved this from PR [Changes Requested] to PR [Needs Review] in Roo Code Roadmap Jun 23, 2025
@mrubens mrubens merged commit 64901c8 into RooCodeInc:main Jun 23, 2025
16 checks passed
@github-project-automation github-project-automation bot moved this from New to Done in Roo Code Roadmap Jun 23, 2025
@github-project-automation github-project-automation bot moved this from PR [Needs Review] to Done in Roo Code Roadmap Jun 23, 2025
cte pushed a commit that referenced this pull request Jun 24, 2025
* fix: address multiple memory leaks in CodeBlock component (CodeBlock_247, CodeBlock_459, CodeBlock_694)

* fix: Address review feedback for CodeBlock memory leak fixes

- Consolidate isMountedRef management into syntax highlighting useEffect
- Unify timeout cleanup patterns for consistent maintainability
- Maintain all existing memory leak protections
- Improve code organization and readability

Addresses review comments from daniel-lxs in PR #4244

---------

Co-authored-by: Daniel Riccio <[email protected]>
Alorse pushed a commit to Alorse/Roo-Code that referenced this pull request Jun 27, 2025
…#4244)

* fix: address multiple memory leaks in CodeBlock component (CodeBlock_247, CodeBlock_459, CodeBlock_694)

* fix: Address review feedback for CodeBlock memory leak fixes

- Consolidate isMountedRef management into syntax highlighting useEffect
- Unify timeout cleanup patterns for consistent maintainability
- Maintain all existing memory leak protections
- Improve code organization and readability

Addresses review comments from daniel-lxs in PR RooCodeInc#4244

---------

Co-authored-by: Daniel Riccio <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working lgtm This PR has been approved by a maintainer PR - Needs Review size:M This PR changes 30-99 lines, ignoring generated files.

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

4 participants