perf: debounce getHTML() dans onUpdate — 400ms au lieu de chaque frappe
Some checks failed
CI / Deploy production (on server) (push) Has been cancelled
CI / Lint, Unit Tests & Build (push) Has been cancelled

getHTML() traverse tout le document ProseMirror à chaque transaction.
Sur les notes longues (500+ blocs), cela causait des lags visibles.
Maintenant debounced à 400ms via setTimeout + clearTimeout.
Le wikilink detection reste synchrone (réactif).
This commit is contained in:
Antigravity
2026-06-20 16:27:30 +00:00
parent ce596fa947
commit 87efb807f3

View File

@@ -359,12 +359,21 @@ export const RichTextEditor = forwardRef<RichTextEditorHandle, RichTextEditorPro
const editorInstanceRef = useRef<Editor | null>(null) const editorInstanceRef = useRef<Editor | null>(null)
const onChangeRef = useRef(onChange) const onChangeRef = useRef(onChange)
onChangeRef.current = onChange onChangeRef.current = onChange
const htmlDebounceRef = useRef<ReturnType<typeof setTimeout> | null>(null)
const emitContentChange = useCallback((html: string) => { const emitContentChange = useCallback((html: string) => {
lastEmittedContent.current = html lastEmittedContent.current = html
onChangeRef.current?.(html) onChangeRef.current?.(html)
}, []) }, [])
// Debounced version for onUpdate — avoids calling getHTML() on every keystroke
const emitContentChangeDebounced = useCallback((editor: any) => {
if (htmlDebounceRef.current) clearTimeout(htmlDebounceRef.current)
htmlDebounceRef.current = setTimeout(() => {
emitContentChange(editor.getHTML())
}, 400)
}, [emitContentChange])
useEffect(() => { useEffect(() => {
if (typeof window === 'undefined') return if (typeof window === 'undefined') return
const checkMobile = () => setIsMobile(window.innerWidth < 768) const checkMobile = () => setIsMobile(window.innerWidth < 768)
@@ -595,8 +604,8 @@ export const RichTextEditor = forwardRef<RichTextEditorHandle, RichTextEditorPro
} }
}, },
onUpdate: ({ editor: e }) => { onUpdate: ({ editor: e }) => {
// Debounce getHTML() — it's expensive on long notes // Debounced getHTML() — avoids traversing the whole doc on every keystroke
emitContentChange(e.getHTML()) emitContentChangeDebounced(e)
if (!e.isEditable) return if (!e.isEditable) return
const { from, empty } = e.state.selection const { from, empty } = e.state.selection
if (!empty) return if (!empty) return