authorgravatar for 206951365+cursor[bot]@users.noreply.github.comcursor[bot] <206951365+cursor[bot]@users.noreply.github.com> 2026-05-07 21:44:30-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-05-07 21:44:30-07:00
log7455472c347de3255a8f9f1306b8c4cd96eac5d4
tree43726d09e33e9b91f7ad80e76588c9597d8e6d37
parent9d919d0bb8d6a2d561464201713117e2d0c588ad
signature Signed by PGP key B5690EEEBB952194

Reduce sidebar selection rerenders (#2560)

Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>

1 files changed, 5 insertions(+), 15 deletions(-)

apps/web/src/components/Sidebar.tsx+5-15
......@@ -341,7 +341,6 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThreadRowP
341341 const threadKey = scopedThreadKey(threadRef);
342342 const lastVisitedAt = useUiStateStore((state) => state.threadLastVisitedAtById[threadKey]);
343343 const isSelected = useThreadSelectionStore((state) => state.selectedThreadKeys.has(threadKey));
344 const hasSelection = useThreadSelectionStore((state) => state.selectedThreadKeys.size > 0);
345344 const runningTerminalIds = useTerminalStateStore(
346345 (state) =>
347346 selectThreadTerminalState(state.terminalStateByThreadKey, threadRef).runningTerminalIds,
......@@ -427,6 +426,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThreadRowP
427426 const handleRowContextMenu = useCallback(
428427 (event: React.MouseEvent) => {
429428 event.preventDefault();
429 const hasSelection = useThreadSelectionStore.getState().hasSelection();
430430 if (hasSelection && isSelected) {
431431 void handleMultiSelectContextMenu({
432432 x: event.clientX,
......@@ -443,14 +443,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThreadRowP
443443 y: event.clientY,
444444 });
445445 },
446 [
447 clearSelection,
448 handleMultiSelectContextMenu,
449 handleThreadContextMenu,
450 hasSelection,
451 isSelected,
452 threadRef,
453 ],
446 [clearSelection, handleMultiSelectContextMenu, handleThreadContextMenu, isSelected, threadRef],
454447 );
455448 const handlePrClick = useCallback(
456449 (event: React.MouseEvent<HTMLButtonElement>) => {
......@@ -964,7 +957,6 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec
964957 const clearSelection = useThreadSelectionStore((state) => state.clearSelection);
965958 const removeFromSelection = useThreadSelectionStore((state) => state.removeFromSelection);
966959 const setSelectionAnchor = useThreadSelectionStore((state) => state.setAnchor);
967 const selectedThreadCount = useThreadSelectionStore((state) => state.selectedThreadKeys.size);
968960 const { copyToClipboard: copyThreadIdToClipboard } = useCopyToClipboard<{
969961 threadId: ThreadId;
970962 }>({
......@@ -1235,7 +1227,7 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec
12351227 event.stopPropagation();
12361228 return;
12371229 }
1238 if (selectedThreadCount > 0) {
1230 if (useThreadSelectionStore.getState().hasSelection()) {
12391231 clearSelection();
12401232 }
12411233 toggleProject(project.projectKey);
......@@ -1244,7 +1236,6 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec
12441236 clearSelection,
12451237 dragInProgressRef,
12461238 project.projectKey,
1247 selectedThreadCount,
12481239 suppressProjectClickAfterDragRef,
12491240 suppressProjectClickForContextMenuRef,
12501241 toggleProject,
......@@ -2833,7 +2824,6 @@ export default function Sidebar() {
28332824 const suppressProjectClickAfterDragRef = useRef(false);
28342825 const suppressProjectClickForContextMenuRef = useRef(false);
28352826 const [desktopUpdateState, setDesktopUpdateState] = useState<DesktopUpdateState | null>(null);
2836 const selectedThreadCount = useThreadSelectionStore((s) => s.selectedThreadKeys.size);
28372827 const clearSelection = useThreadSelectionStore((s) => s.clearSelection);
28382828 const setSelectionAnchor = useThreadSelectionStore((s) => s.setAnchor);
28392829 const platform = navigator.platform;
......@@ -3279,7 +3269,7 @@ export default function Sidebar() {
32793269
32803270 useEffect(() => {
32813271 const onMouseDown = (event: globalThis.MouseEvent) => {
3282 if (selectedThreadCount === 0) return;
3272 if (!useThreadSelectionStore.getState().hasSelection()) return;
32833273 const target = event.target instanceof HTMLElement ? event.target : null;
32843274 if (!shouldClearThreadSelectionOnMouseDown(target)) return;
32853275 clearSelection();
......@@ -3289,7 +3279,7 @@ export default function Sidebar() {
32893279 return () => {
32903280 window.removeEventListener("mousedown", onMouseDown);
32913281 };
3292 }, [clearSelection, selectedThreadCount]);
3282 }, [clearSelection]);
32933283
32943284 useEffect(() => {
32953285 if (!isElectron) return;