Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 2025-04-28 - Optimize React list sorting
**Learning:** For optimal performance in React list rendering, prefer lexicographical string comparison (e.g., `b.updatedAt.localeCompare(a.updatedAt)`) over `new Date()` allocation when sorting by ISO 8601 timestamps, and always memoize the derived list to prevent O(n log n) object allocation overhead on re-renders.
**Action:** Always memoize derived lists and avoid `new Date()` object allocation in sorting functions for ISO 8601 strings.
Comment on lines +2 to +3

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

It is better to recommend direct string comparison over localeCompare for ISO 8601 timestamps to achieve better performance, especially since this is documented as an optimization learning.

Suggested change
**Learning:** For optimal performance in React list rendering, prefer lexicographical string comparison (e.g., `b.updatedAt.localeCompare(a.updatedAt)`) over `new Date()` allocation when sorting by ISO 8601 timestamps, and always memoize the derived list to prevent O(n log n) object allocation overhead on re-renders.
**Action:** Always memoize derived lists and avoid `new Date()` object allocation in sorting functions for ISO 8601 strings.
**Learning:** For optimal performance in React list rendering, prefer direct string comparison (e.g., `a.updatedAt > b.updatedAt ? -1 : 1`) over `new Date()` allocation or `localeCompare` when sorting by ISO 8601 timestamps, and always memoize the derived list to prevent O(n log n) object allocation overhead on re-renders.
**Action:** Always memoize derived lists and avoid `new Date()` object allocation and `localeCompare` in sorting functions for ISO 8601 strings.

13 changes: 7 additions & 6 deletions apps/app/src/components/ConversationsSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 lexicographical string comparison for O(n log n) object allocation overhead on re-renders
const sortedConversations = useMemo(() => {
return [...conversations].sort((a, b) =>
b.updatedAt.localeCompare(a.updatedAt),
);
Comment on lines +58 to +61

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Potentially incorrect sorting of conversations:
The sorting logic uses localeCompare on the updatedAt field, which assumes the date strings are in ISO 8601 format. If the date strings are not consistently formatted, this may result in incorrect ordering. For robust date sorting, consider parsing the dates and comparing their numeric values:

return [...conversations].sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());

This ensures conversations are sorted by actual date values, regardless of string format.

}, [conversations]);
Comment on lines +57 to +62

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

While localeCompare is correct for string comparison, it is significantly slower than direct string comparison operators (<, >) because it involves locale-aware collation logic. For ISO 8601 strings, which are lexicographically sortable by design, direct comparison is much more efficient. Since this PR specifically aims to optimize performance, using direct comparison is preferred. Additionally, the comment phrasing "for O(n log n) object allocation overhead" is slightly confusing; it would be clearer to state that it "avoids" this overhead.

Suggested change
// ⚑ Bolt: Memoize the sorting and use lexicographical string comparison for O(n log n) object allocation overhead on re-renders
const sortedConversations = useMemo(() => {
return [...conversations].sort((a, b) =>
b.updatedAt.localeCompare(a.updatedAt),
);
}, [conversations]);
// ⚑ Bolt: Memoize the sorting and use direct string comparison to avoid O(n log n) object allocation overhead on re-renders
const sortedConversations = useMemo(() => {
return [...conversations].sort((a, b) =>
a.updatedAt > b.updatedAt ? -1 : a.updatedAt < b.updatedAt ? 1 : 0,
);
}, [conversations]);


const handleDoubleClick = (conv: { id: string; title: string }) => {
setEditingId(conv.id);
Expand Down
Loading