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-27 - Fast Lexicographical Time Sorting
**Learning:** In heavily used UI components like React sidebars that display lists updated in real-time, relying on `.sort()` blocks combined with inline `new Date(string).getTime()` allocation causes measurable re-render lag due to memory allocation and date parsing overhead on every tick. For standard ISO 8601 strings (like `updatedAt`), the sorting structure is inherently chronologically sound and allows for fast alphabetical comparison.
**Action:** When implementing real-time list sorting by ISO timestamp on the frontend, always combine array memoization (`useMemo`) with native `.localeCompare()` instead of allocating `Date` objects on every re-render.
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 localeCompare for timestamps instead of parsing Date
const sortedConversations = useMemo(() => {
return [...conversations].sort((a, b) =>
b.updatedAt.localeCompare(a.updatedAt),
);
Comment on lines +59 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.

medium

Using direct string comparison (>) for ISO 8601 timestamps is significantly more efficient than localeCompare. Since ISO strings are designed to be lexicographically sortable, the locale-aware collation logic in localeCompare is unnecessary and adds avoidable overhead in this performance-critical path.

Suggested change
return [...conversations].sort((a, b) =>
b.updatedAt.localeCompare(a.updatedAt),
);
return [...conversations].sort((a, b) =>
b.updatedAt > a.updatedAt ? 1 : b.updatedAt < a.updatedAt ? -1 : 0,
);

}, [conversations]);

Comment on lines +57 to 63

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Using localeCompare to sort timestamps (as in b.updatedAt.localeCompare(a.updatedAt)) assumes all timestamps are in the same, lexicographically sortable format (e.g., ISO 8601). If the format changes or timezones are introduced, this could result in incorrect ordering. For greater robustness, consider parsing the timestamps to Date objects and comparing numerically:

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

This approach is more resilient to format changes and ensures correct chronological ordering.

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