diff --git a/.jules/bolt.md b/.jules/bolt.md index fa2deda3f..a8d8d4285 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -26,3 +26,6 @@ ## 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. +## 2025-03-01 - Memoizing EmailList inline array map +**Learning:** Inline mapping of arrays inside JSX in the \`EmailList\` component causes O(N) recalculation on every render. +**Action:** Wrap inline JSX elements that map over emails in a \`useMemo\` hook with specific dependencies to prevent rendering bottlenecks. diff --git a/frontend/src/components/EmailList.tsx b/frontend/src/components/EmailList.tsx index 6dbb722ea..260e9e8d8 100644 --- a/frontend/src/components/EmailList.tsx +++ b/frontend/src/components/EmailList.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useRef, useState, memo } from 'react'; +import React, { useCallback, useEffect, useRef, useState, memo, useMemo } from 'react'; import { apiClient } from '@/lib/api-client'; import { ScrollArea } from "@/components/ui/scroll-area"; import { Avatar, AvatarFallback } from "@/components/ui/avatar"; @@ -173,6 +173,17 @@ export function EmailList({ }; const searchBusy = isSearching || loading; + const emailListNodes = useMemo(() => { + return emails.map((email: EmailItem) => ( + + )); + }, [emails, selectedEmailId, onSelectEmail]); + return (
@@ -259,14 +270,7 @@ export function EmailList({

{folderCopy.emptyBody}

) : ( - emails.map((email: EmailItem) => ( - - )) + emailListNodes )}