From 2b4b6f41659e3e6e074f0ed3b2e811095adb8d50 Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 1 Aug 2026 23:02:46 +0000 Subject: [PATCH] fix: stabilize NoteEditor/NoteEditorPane memoization with useCallback Root cause: inline arrow functions for onDelete and onSave props created new references every render, breaking React.memo and causing editor re-renders that steal focus. --- apps/web/src/routes/_app/notes.tsx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/web/src/routes/_app/notes.tsx b/apps/web/src/routes/_app/notes.tsx index 7badeb6..921c3c2 100644 --- a/apps/web/src/routes/_app/notes.tsx +++ b/apps/web/src/routes/_app/notes.tsx @@ -1,4 +1,4 @@ -import { useState, useRef, useEffect, memo } from "react"; +import { useState, useRef, useEffect, memo, useCallback } from "react"; import { createRoute } from "@tanstack/react-router"; import { Route as appRoute } from "../_app"; import { useMutation, useQueryClient } from "@tanstack/react-query"; @@ -90,6 +90,10 @@ const NoteEditorPane = memo(function NoteEditorPane({ note, onDelete }: { note: onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["notes"] }); }, }); + const handleSave = useCallback((html: string) => { + updateMutation.mutate({ id: note.id, data: { content: html } }); + }, [note.id, updateMutation]); + return ( <>
@@ -121,7 +125,7 @@ const NoteEditorPane = memo(function NoteEditorPane({ note, onDelete }: { note:
- { updateMutation.mutate({ id: note.id, data: { content: html } }); }} /> +
{/* Backlinks section */} {showBacklinks && note.backlinks && note.backlinks.length > 0 && ( @@ -192,6 +196,10 @@ function NotesPage() { const selectedNote = selectedNoteRef.current; + const handleDeleteNote = useCallback((id: string) => { + deleteMutation.mutate(id); + }, [deleteMutation]); + return (
{/* Left pane - note list */} @@ -240,7 +248,7 @@ function NotesPage() { {/* Right pane - editor (memoized, won't re-render on parent state changes) */}
{selectedNote ? ( - deleteMutation.mutate(id)} /> + ) : (