fix(react): useEditor should not destroy still mounted instances (#5338)

This forces the editor to re-use the editor instance that existed prior to an unmount and remount of the same component.
This fixes a bug in `React.StrictMode` introduced with the latest performance updates by PR #5161
This commit is contained in:
Nick Perez 2024-07-13 10:59:33 +02:00 committed by GitHub
parent db0d007660
commit 1110280b2b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 25 additions and 2 deletions

View File

@ -0,0 +1,5 @@
---
"@tiptap/react": patch
---
Fixes strict mode accidentally destroying the editor instance

View File

@ -93,7 +93,7 @@ function EditorInstance({ shouldOptimizeRendering }) {
)
}
export default () => {
const EditorControls = () => {
const [shouldOptimizeRendering, setShouldOptimizeRendering] = React.useState(true)
return (
@ -128,3 +128,11 @@ export default () => {
</>
)
}
export default () => {
return (
<React.StrictMode>
<EditorControls />
</React.StrictMode>
)
}

View File

@ -57,6 +57,7 @@ export function useEditor(
options: UseEditorOptions = {},
deps: DependencyList = [],
): Editor | null {
const isMounted = useRef(false)
const [editor, setEditor] = useState(() => {
if (options.immediatelyRender === undefined) {
if (isSSR || isNext) {
@ -220,12 +221,21 @@ export function useEditor(
* only be called when the component is removed from the DOM, since it has no deps.
* */
useEffect(() => {
isMounted.current = true
return () => {
isMounted.current = false
if (editor) {
// We need to destroy the editor asynchronously to avoid memory leaks
// because the editor instance is still being used in the component.
setTimeout(() => (editor.isDestroyed ? null : editor.destroy()))
setTimeout(() => {
// re-use the editor instance if it hasn't been destroyed yet
// and the component is still mounted
// otherwise, asynchronously destroy the editor instance
if (!isMounted.current && !editor.isDestroyed) {
editor.destroy()
}
})
}
}
}, [])