Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(react): optimize useEditor and useEditorState to reduce number of instances created while being performant #5432 #5445

Merged
merged 5 commits into from
Aug 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .changeset/smooth-rice-obey.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
"@tiptap/react": patch
---

Optimize `useEditor` and `useEditorState` to reduce number of instances created while still being performant #5432

The core of this change is two-fold:
- have the effect run on every render (i.e. without a dep array)
- schedule destruction of instances, but bail on the actual destruction if the instance was still mounted and a new instance had not been created yet

It should plug a memory leak, where editor instances could be created but not cleaned up in strict mode.
As well as fixing a bug where a re-render, with deps, was not applying new options that were set on `useEditor`.
9 changes: 9 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ module.exports = {
node: true,
},
overrides: [
{
files: [
'./**/*.ts',
'./**/*.tsx',
'./**/*.js',
'./**/*.jsx',
],
extends: ['plugin:react-hooks/recommended'],
},
{
files: [
'./**/*.ts',
Expand Down
8 changes: 4 additions & 4 deletions demos/src/Commands/Cut/React/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@ import StarterKit from '@tiptap/starter-kit'
import React, { useCallback } from 'react'

const MenuBar = ({ editor }) => {
if (!editor) {
return null
}

const onCutToStart = useCallback(() => {
editor.chain().cut({ from: editor.state.selection.$from.pos, to: editor.state.selection.$to.pos }, 1).run()
}, [editor])
Expand All @@ -20,6 +16,10 @@ const MenuBar = ({ editor }) => {
editor.chain().cut({ from: editor.state.selection.$from.pos, to: editor.state.selection.$to.pos }, editor.state.doc.nodeSize - 2).run()
}, [editor])

if (!editor) {
return null
}

return (
<div className="control-group">
<div className="button-group">
Expand Down
8 changes: 5 additions & 3 deletions demos/src/Examples/Performance/React/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ function EditorInstance({ shouldOptimizeRendering }) {
})

return (
<>
<div>
<div className="control-group">
<div>Number of renders: <span id="render-count">{countRenderRef.current}</span></div>
</div>
Expand All @@ -89,12 +89,13 @@ function EditorInstance({ shouldOptimizeRendering }) {
</BubbleMenu>
)}
<EditorContent editor={editor} />
</>
</div>
)
}

const EditorControls = () => {
const [shouldOptimizeRendering, setShouldOptimizeRendering] = React.useState(true)
const [rendered, setRendered] = React.useState(true)

return (
<>
Expand Down Expand Up @@ -123,8 +124,9 @@ const EditorControls = () => {
Render every transaction (default behavior)
</label>
</div>
<button onClick={() => setRendered(a => !a)}>Toggle rendered</button>
</div>
<EditorInstance shouldOptimizeRendering={shouldOptimizeRendering} />
{rendered && <EditorInstance shouldOptimizeRendering={shouldOptimizeRendering} />}
</>
)
}
Expand Down
1 change: 1 addition & 0 deletions demos/src/GuideContent/ReadOnly/React/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import React, { useEffect, useState } from 'react'
export default () => {
const [editable, setEditable] = useState(false)
const editor = useEditor({
shouldRerenderOnTransaction: false,
editable,
content: `
<p>
Expand Down
Loading