Skip to content

fix(logs): stabilize callbacks and memo-wrap components to eliminate re-render cascade#3222

Merged
waleedlatif1 merged 5 commits intostagingfrom
fix/logs-loading
Feb 15, 2026
Merged

fix(logs): stabilize callbacks and memo-wrap components to eliminate re-render cascade#3222
waleedlatif1 merged 5 commits intostagingfrom
fix/logs-loading

Conversation

@waleedlatif1
Copy link
Collaborator

@waleedlatif1 waleedlatif1 commented Feb 14, 2026

Summary

  • Replace selectedLogId + isSidebarOpen useState with useReducer for stable dispatch
  • Stabilize all callbacks (handleLogClick, handleNavigateNext/Prev, handleRefresh, handleToggleLive, loadMoreLogs, handleExport) via refs and stable dispatch
  • Memo-wrap LogsToolbar, LogRowContextMenu, NotificationSettings, WorkflowOutputSection, Dashboard, SubBlockRow, ViewerInner
  • Add custom areStatusBarPropsEqual comparator for structural segment comparison
  • Add execution data stabilization layer in Dashboard to reuse previous references across polls
  • Fix WorkflowsList/StatusBar barrel exports that were bypassing memo
  • Add timer cleanup for all setTimeout calls to prevent unmounted state updates
  • Remove dead code: scrollContainerRef, barsAreaRef, useAlertRule state, as any cast
  • Fix relative import to absolute path

Type of Change

  • Bug fix
  • Performance improvement

Testing

Tested manually with React Scan profiling

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel
Copy link

vercel bot commented Feb 14, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Feb 15, 2026 1:44am

Request Review

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 14, 2026

Greptile Overview

Greptile Summary

This PR implements comprehensive performance optimizations to eliminate re-render cascades in the logs page. The changes are well-structured and address multiple sources of unnecessary re-renders.

Key improvements:

  • Replaced useState with useReducer for log selection state, providing a stable dispatch function that prevents callback recreation
  • Stabilized all event handlers (handleLogClick, navigation, refresh, toggle live, export) using refs to read current values instead of closure captures
  • Added execution data stabilization in Dashboard to reuse object references across polls when data hasn't structurally changed
  • Memo-wrapped 7+ components with custom equality comparators where needed (StatusBar, WorkflowOutputSection)
  • Fixed barrel exports that were bypassing memo wrappers by removing default exports
  • Implemented proper timer cleanup with refreshTimersRef to prevent memory leaks and state updates after unmount
  • Added hover prefetch for instant log detail panel rendering
  • Changed refetchInterval to callback-based for smarter polling (only active logs)
  • Removed dead code: unused refs, useAlertRule state, unnecessary type casts

Previously flagged issues acknowledged:
The PR description acknowledges the JSON.stringify performance concern in WorkflowOutputSection comparator and the initialData vs placeholderData trade-off in the query hook. These are acceptable for the current scale.

Confidence Score: 4/5

  • This PR is safe to merge with minimal risk - the changes are defensive performance optimizations that don't alter business logic
  • Score reflects thorough performance optimization work with proper patterns (useReducer, refs, memo). The changes are well-tested manually with React Scan profiling. Minor score reduction due to: 1) the custom comparators adding complexity that needs monitoring, 2) the acknowledged trade-offs in JSON.stringify and initialData patterns, and 3) lack of automated tests for the optimization behavior
  • Pay attention to logs.tsx and dashboard.tsx - these contain the most complex state management changes. Monitor the custom areStatusBarPropsEqual comparator to ensure it remains in sync if StatusBarSegment interface changes

Important Files Changed

Filename Overview
apps/sim/app/workspace/[workspaceId]/logs/logs.tsx Replaced useState with useReducer for stable dispatch, stabilized all callbacks with refs, added timer cleanup, and added hover prefetch
apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/dashboard.tsx Added execution data stabilization layer to reuse references across polls, memo-wrapped component, removed unused refs
apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/components/status-bar/status-bar.tsx Added custom structural equality comparator for memo to prevent re-renders on identical poll data
apps/sim/app/workspace/[workspaceId]/logs/components/log-details/log-details.tsx Memo-wrapped WorkflowOutputSection with custom comparator and added timer cleanup for copy timeout
apps/sim/hooks/queries/logs.ts Changed refetchInterval to support callback, added initialData from list cache, and added prefetchLogDetail function

Flowchart

flowchart TD
    A[User Action] --> B{Action Type}
    
    B -->|Click Log| C[dispatch TOGGLE_LOG]
    B -->|Navigate| D[handleNavigateNext/Prev]
    B -->|Refresh| E[handleRefresh]
    B -->|Toggle Live| F[handleToggleLive]
    B -->|Hover Log| G[prefetchLogDetail]
    
    C --> H[useReducer updates state]
    D --> I[Read from logsRef.current]
    E --> J[Read from refs, start timer]
    F --> K[setIsLive updater, start timer]
    G --> L[QueryClient prefetch]
    
    H --> M[Stable dispatch prevents re-render]
    I --> M
    J --> N[refreshTimersRef tracks cleanup]
    K --> N
    L --> O[Instant panel on click]
    
    M --> P[Memoized components skip render]
    N --> Q[Cleanup on unmount]
    
    P --> R[StatusBar custom comparator]
    P --> S[Dashboard execution stabilization]
    
    R --> T[Structural segment comparison]
    S --> U[Reuse prev refs if data unchanged]
    
    T --> V[No re-render cascade]
    U --> V
Loading

Last reviewed commit: ca0105a

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

3 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 14, 2026

Additional Comments (1)

apps/sim/app/workspace/[workspaceId]/logs/components/logs-list/logs-list.tsx
Missing onHover in memo comparison

The custom arePropsEqual for LogRow doesn't include onHover in its equality check. Since this PR adds onHover as a new prop that's used inside the component (via handleMouseEnter), it should be included here for correctness.

In practice this won't cause a bug today because handleLogHover in the parent has a stable reference (queryClient from useQueryClient() is stable). However, if the handleLogHover dependencies ever change, this memo would silently serve a stale callback. It's best to include it now for forward-compatibility.

Note that onClick and onContextMenu have the same pre-existing omission, but since this PR introduces onHover, adding it here would be consistent with addressing this gap incrementally.

  (prevProps, nextProps) => {
    return (
      prevProps.log.id === nextProps.log.id &&
      prevProps.log.duration === nextProps.log.duration &&
      prevProps.log.status === nextProps.log.status &&
      prevProps.isSelected === nextProps.isSelected &&
      prevProps.onHover === nextProps.onHover
    )
  }

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@waleedlatif1 waleedlatif1 changed the title fix(logs): instant log detail panel with initialData and hover prefetch fix(logs): stabilize callbacks and memo-wrap components to eliminate re-render cascade Feb 14, 2026
@waleedlatif1
Copy link
Collaborator Author

@cursor review
@greptile

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

14 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

@waleedlatif1
Copy link
Collaborator Author

@cursor review

@waleedlatif1
Copy link
Collaborator Author

@cursor review
@greptile

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

14 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

@waleedlatif1
Copy link
Collaborator Author

@cursor review
@greptile

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

14 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

@waleedlatif1 waleedlatif1 merged commit 92b4f77 into staging Feb 15, 2026
12 checks passed
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.

1 participant