-
Notifications
You must be signed in to change notification settings - Fork 1
⚡ Bolt: [performance improvement] Optimize conversation list sorting #497
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| ## 2024-04-29 - Optimize ISO 8601 timestamp sorting in React lists | ||
| **Learning:** In React list rendering, sorting by `new Date(ISOString).getTime()` causes significant object allocation overhead on re-renders, especially for larger lists. While `localeCompare` avoids `Date` allocation, raw string comparison (`> / <`) is even faster for raw ASCII strings like ISO dates, avoiding locale checking overhead. | ||
| **Action:** Use `b.updatedAt > a.updatedAt ? 1 : b.updatedAt < a.updatedAt ? -1 : 0` instead of `new Date()` allocation or `localeCompare` when sorting by ISO 8601 timestamps, and always memoize derived lists with `useMemo` to prevent redundant O(n log n) sorting operations on every re-render. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5029,10 +5029,13 @@ export function AppProvider({ children }: { children: ReactNode }) { | |
| ? { ...c, updatedAt: new Date().toISOString() } | ||
| : c, | ||
| ); | ||
| return updated.sort( | ||
| (a, b) => | ||
| new Date(b.updatedAt).getTime() - | ||
| new Date(a.updatedAt).getTime(), | ||
| // ⚡ Bolt: Use raw string comparison for ISO 8601 strings to avoid Date allocation | ||
| return updated.sort((a, b) => | ||
| b.updatedAt > a.updatedAt | ||
| ? 1 | ||
| : b.updatedAt < a.updatedAt | ||
| ? -1 | ||
| : 0, | ||
| ); | ||
| }); | ||
| }, | ||
|
|
@@ -5046,10 +5049,13 @@ export function AppProvider({ children }: { children: ReactNode }) { | |
| if (conv?.id) { | ||
| setConversations((prev) => { | ||
| const updated = prev.map((c) => (c.id === conv.id ? conv : c)); | ||
| return updated.sort( | ||
| (a, b) => | ||
| new Date(b.updatedAt).getTime() - | ||
| new Date(a.updatedAt).getTime(), | ||
| // ⚡ Bolt: Use raw string comparison for ISO 8601 strings to avoid Date allocation | ||
| return updated.sort((a, b) => | ||
| b.updatedAt > a.updatedAt | ||
| ? 1 | ||
| : b.updatedAt < a.updatedAt | ||
| ? -1 | ||
| : 0, | ||
| ); | ||
|
Comment on lines
+5053
to
5059
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This sorting logic is identical to the one used in the |
||
| }); | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,7 +2,7 @@ | |
| * Conversations sidebar component — left sidebar with conversation list. | ||
| */ | ||
|
|
||
| import { useEffect, useRef, useState } from "react"; | ||
| import { useEffect, useMemo, useRef, useState } from "react"; | ||
| import { useApp } from "../AppContext"; | ||
|
|
||
| interface ConversationsSidebarProps { | ||
|
|
@@ -54,11 +54,12 @@ export function ConversationsSidebar({ | |
| } | ||
| }, [editingId]); | ||
|
|
||
| const sortedConversations = [...conversations].sort((a, b) => { | ||
| const aTime = new Date(a.updatedAt).getTime(); | ||
| const bTime = new Date(b.updatedAt).getTime(); | ||
| return bTime - aTime; | ||
| }); | ||
| // ⚡ Bolt: Memoize the sorting and use raw string comparison for ISO 8601 strings to prevent O(n log n) object allocation overhead on re-renders | ||
| const sortedConversations = useMemo(() => { | ||
| return [...conversations].sort((a, b) => | ||
| b.updatedAt > a.updatedAt ? 1 : b.updatedAt < a.updatedAt ? -1 : 0, | ||
| ); | ||
| }, [conversations]); | ||
|
Comment on lines
+58
to
+62
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Potential Sorting Order Issue: return [...conversations].sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));This ensures the newest conversations are at the top of the sidebar. |
||
|
|
||
| const handleDoubleClick = (conv: { id: string; title: string }) => { | ||
| setEditingId(conv.id); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The sorting logic using nested ternary operators is somewhat difficult to read. While the raw string comparison is efficient, using a more standard conditional structure or a helper function would improve maintainability. Additionally, this exact logic is duplicated later in the same file.