From 3ca65076632940469c5e9ca5bb6344b601d438da Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Thu, 13 Aug 2026 01:24:07 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20Bolt:=20[=EC=84=B1=EB=8A=A5=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0]=20EmailDetail=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EB=A6=AC=EB=A0=8C=EB=8D=94=EB=A7=81=20=EC=B5=9C?= =?UTF-8?q?=EC=A0=81=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .jules/bolt.md | 3 +++ frontend/src/components/EmailDetail.tsx | 9 ++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index 97d21a9e6..fa2deda3f 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -23,3 +23,6 @@ **Learning:** When generating derived UI state in `useMemo` that joins separate data arrays (like graph edges referencing node IDs), calling helper functions that use `Array.prototype.find()` for every item creates an `O(M * N)` bottleneck. **Action:** When a loop needs to repeatedly look up related items from another array by ID, pre-compute an `O(N)` `Map` before the loop and use `map.get()` for `O(1)` lookups instead of inline array `.find()` calls. +## 2024-05-24 - [React Component Memoization] +**Learning:** In React components like `WorkspaceHome`, when layout state or polling changes trigger parent re-renders, expensive child components like `EmailDetail` will also re-render unnecessarily if not memoized. +**Action:** Always consider `React.memo` for heavy child components that rely on stable props (like IDs) when the parent component has frequent unrelated state updates. diff --git a/frontend/src/components/EmailDetail.tsx b/frontend/src/components/EmailDetail.tsx index 35263d783..5a6767085 100644 --- a/frontend/src/components/EmailDetail.tsx +++ b/frontend/src/components/EmailDetail.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useRef, useState } from 'react'; +import React, { useCallback, useEffect, useRef, useState, memo } from 'react'; import { apiClient } from '@/lib/api-client'; import { Separator } from "@/components/ui/separator"; import { Avatar, AvatarFallback } from "@/components/ui/avatar"; @@ -102,7 +102,10 @@ function normalizeLlmData(payload: unknown): LlmData { }; } -export function EmailDetail({ emailId, actionCommand = null }: { emailId: number | null; actionCommand?: EmailDetailActionCommand | null }) { +// ⚡ Bolt: Memoized EmailDetail to prevent unnecessary re-renders +// 🎯 Why: Re-renders of EmailDetail when the parent components (like WorkspaceHome) re-render can cause performance issues, especially when switching active layout tabs or receiving polling updates that don't affect the selected email. +// 📊 Impact: Significantly reduces React reconciliation work when the workspace state changes but the selected email remains the same. +export const EmailDetail = memo(function EmailDetail({ emailId, actionCommand = null }: { emailId: number | null; actionCommand?: EmailDetailActionCommand | null }) { const [email, setEmail] = useState(null); const [threadEmails, setThreadEmails] = useState([]); const [llmData, setLlmData] = useState(null); @@ -883,4 +886,4 @@ export function EmailDetail({ emailId, actionCommand = null }: { emailId: number /> ); -} +});