[Bug]: Node Views Causes Extra Re-draws When EditorContent Mounts
Introduction
When using React with extensions that include node views in Prosemirror, the editor is initially re-drawn several times. This can cause performance issues, particularly when prosemirror-view
resets the text selection. In this article, we will explore the issue, provide a code example, and discuss the expected behavior.
Affected Packages and Version
Affected Packages
core
react
Version(s)
2.11.7
Bug Description
When using React with extensions that include node views, the editor is initially re-drawn several times. prosemirror-view
's internal updateStateInner
method is called three times, and the document is re-drawn because the node views are changing. This can be seen in the prosemirror-view
source code, specifically in the updateStateInner
method.
// https://github.com/ProseMirror/prosemirror-view/blob/4867a987d4e54768492dc167bf3a8340e2dd91f5/src/index.ts#L166
updateStateInner(state, dispatch, view) {
// ...
if (view.state.docChanged) {
view.updateState(state);
}
// ...
}
As you can see, the updateStateInner
method is called three times, and the document is re-drawn each time.
Browser Used
- Chrome
Code Example URL
Expected Behavior
Draw the document only once on mount.
Additional Context (Optional)
I think that updateState
is called three times:
- First when the editor is created: The editor only contains the node views created directly with a Prosemirror plugin via
addProseMirrorPlugins
. The document is drawn. - The editor then calls
createNodeViews
: Which again callsupdateState
. The editor now contains the node views created viaaddNodeView
. The document is redrawn. - Finally, the
EditorContent
component callscreateNodeViews
again: But the node views are erroneously considered different, so the document is redrawn a third time.
// https://github.com/ueberdosis/tiptap/blob/6ceff32242dc815acb121717752467f205d52e42/packages/core/src/Editor.ts#L382
editor.create();
// https://github.com/ueberdosis/tiptap/blob/6ceff32242dc815acb121717752467f205d52e42/packages/core/src/Editor.ts#L384
editor.createNodeViews();
// https://github.com/ueberdosis/tiptap/blob/6ceff32242dc815acb121717752467f205d52e42/packages/react/src/EditorContent.tsx#L161
EditorContent.createNodeViews();
Workaround
I can avoid this issue by avoiding addNodeView
and only using addProsemirrorPlugins
.
Dependency Updates
- [x] Yes, I've updated my dependencies.
Conclusion
In conclusion, the issue of node views causing extra re-draws when EditorContent
mounts is a known problem in Prosemirror. By avoiding addNodeView
and only using addProsemirrorPlugins
, we can avoid this issue. However, this is just a workaround, and a proper fix is needed to resolve this issue once and for all.
Future Work
In the future, we can work on resolving this issue by:
- Investigating why
updateState
is called three times - Fixing the issue with
createNodeViews
being called multiple times - Improving the performance of
prosemirror-view
to reduce the number of re-draws
Q: What is the issue with node views causing extra re-draws when EditorContent mounts?
A: The issue is that prosemirror-view
's internal updateStateInner
method is called three times, and the document is re-drawn because the node views are changing. This can cause performance issues, particularly when prosemirror-view
resets the text selection.
Q: Why is updateState
called three times?
A: updateState
is called three times because of the following sequence of events:
- First when the editor is created: The editor only contains the node views created directly with a Prosemirror plugin via
addProseMirrorPlugins
. The document is drawn. - The editor then calls
createNodeViews
: Which again callsupdateState
. The editor now contains the node views created viaaddNodeView
. The document is redrawn. - Finally, the
EditorContent
component callscreateNodeViews
again: But the node views are erroneously considered different, so the document is redrawn a third time.
Q: How can I avoid this issue?
A: You can avoid this issue by avoiding addNodeView
and only using addProsemirrorPlugins
.
Q: What are the performance implications of this issue?
A: The performance implications of this issue are that the editor is re-drawn multiple times, which can cause performance issues, particularly when prosemirror-view
resets the text selection.
Q: How can I improve the performance of my editor?
A: To improve the performance of your editor, you can:
- Avoid using
addNodeView
and only useaddProsemirrorPlugins
- Optimize your node views to reduce the number of re-draws
- Use a more efficient rendering engine, such as
prosemirror-view
'supdateStateInner
method
Q: Is this issue specific to Prosemirror?
A: No, this issue is not specific to Prosemirror. It can occur in any rich text editor that uses a similar architecture.
Q: How can I report this issue to the Prosemirror team?
A: You can report this issue to the Prosemirror team by opening an issue on the Prosemirror GitHub repository.
Q: What is the expected behavior of the editor when EditorContent
mounts?
A: The expected behavior of the editor when EditorContent
mounts is to draw the document only once.
Q: How can I verify that the issue is fixed?
A: To verify that the issue is fixed, you can:
- Check that
updateState
is only called once - Verify that the document is only drawn once
- Test the editor's performance to ensure that it is improved
By following these steps, you can help to resolve this issue and improve the performance of your editor.