From d9d223396040edcd7b2e78edafaeba1c40c788b8 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 20 Jan 2026 18:08:56 +0000 Subject: [PATCH] fix: prevent extensions recreation by stabilizing suggestion config dependencies The root cause of broken autocompletion was that suggestion configs were being extracted via .find() outside useMemo, creating new object references on every render. These unstable references were then used as dependencies for the extensions useMemo, causing TipTap extensions to be recreated on every single render. This destroyed the suggestion system's internal state including popup visibility and search results. Changes: - Move .find() calls inside the extensions useMemo - Replace individual config dependencies with stable 'suggestions' array - Extensions now only recreate when suggestions actually change (rare) This matches React best practices: avoid computing values outside useMemo when those values are used as dependencies, as they create unstable references that defeat memoization. The issue was NOT with TipTap's async handling (my first fix was wrong), but with React's dependency tracking and object reference stability. --- src/components/editor/NostrEditor.tsx | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/components/editor/NostrEditor.tsx b/src/components/editor/NostrEditor.tsx index fc96d9c..ba0f573 100644 --- a/src/components/editor/NostrEditor.tsx +++ b/src/components/editor/NostrEditor.tsx @@ -543,13 +543,13 @@ export const NostrEditor = forwardRef( handleSubmitRef.current = handleSubmit; - // Find suggestion configs - const mentionConfig = suggestions.find((s) => s.char === "@"); - const emojiConfig = suggestions.find((s) => s.char === ":"); - const slashConfig = suggestions.find((s) => s.char === "/"); - // Build extensions array const extensions = useMemo(() => { + // Find suggestion configs inside useMemo to avoid recreating extensions on every render + const mentionConfig = suggestions.find((s) => s.char === "@"); + const emojiConfig = suggestions.find((s) => s.char === ":"); + const slashConfig = suggestions.find((s) => s.char === "/"); + const isMobile = "ontouchstart" in window || navigator.maxTouchPoints > 0; // Custom extension for keyboard shortcuts @@ -711,14 +711,7 @@ export const NostrEditor = forwardRef( } return exts; - }, [ - submitBehavior, - placeholder, - blobPreview, - mentionConfig, - emojiConfig, - slashConfig, - ]); + }, [submitBehavior, placeholder, blobPreview, suggestions]); const editor = useEditor({ extensions,