-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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): resolves React NodeView performance issues #5273
Conversation
✅ Deploy Preview for tiptap-embed ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
10b4a50
to
575a467
Compare
72fecbe
to
ad0bdfc
Compare
575a467
to
a26ed74
Compare
ad0bdfc
to
3a066ba
Compare
a26ed74
to
b65ac57
Compare
3a066ba
to
62a37d7
Compare
b65ac57
to
607e939
Compare
62a37d7
to
2b0e7e0
Compare
🦋 Changeset detectedLatest commit: b379aa2 The changes in this PR will be included in the next version bump. This PR includes changesets to release 54 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
204e7c5
to
f157449
Compare
2b0e7e0
to
e0b53a4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM - lets see how well it performs! :)
@@ -6,6 +6,7 @@ import { | |||
} from '@tiptap/react' | |||
|
|||
const ParagraphComponent = ({ node }) => { | |||
console.count('render') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Stray console log here
4f15693
to
572842e
Compare
@@ -121,7 +122,15 @@ export class ReactRenderer<R = unknown, P = unknown> { | |||
}) | |||
} | |||
|
|||
this.render() | |||
if (this.editor.isInitialized) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't this call flushSync every time setRenderer
was called after the editor has initialized?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is in the constructor function, for the initial render.
Before this change, we were calling flushSync on every setRenderer call (with maybeFlushSync
).
With this change, it will only flush sync on the first render and then every update after will be handled with a useSyncExternalStore
(i.e. letting React "pick up" the changes whenever it feels like it)
a662e8f
to
adb6d7b
Compare
55e6662
to
32720c8
Compare
Isn't removing I'm not sure, but looking at the commit history, it might've been added to account for this scenario in the first place. |
That is what this code & comment is regarding: https://github.com/ueberdosis/tiptap/pull/5273/files#r1676838961 |
I might be mistaken, but from what I understand this is regarding editor initialization, but a transaction like that might occur at any point in time after the editor is already initialized, isn't that the case? |
So this PR only skips flushSync if the editor has not yet initialized (because react can't render new nodes when the editor is just being initialized). So, in the case of an already initialized editor, it will use flushSync to force the node view to be created synchronously so that the selection can be moved into the element synchronously. Once the element is created though, this no longer is a problem because the DOM element is present (since it already is initialized and in the dom) so prosemirror can move the selection into that element. I will definitely double check to verify this though |
It is possible to reproduce the cursor issue with our in-house tiptap editor (it's why I never opened a PR for my "fix" from #4492). I can see whether I can reproduce it, and if the problem remains I'll try to share a reduced test case. |
Alright, I think that this PR resolves that cursor issue (by |
I can confirm that we don't see the cursor placement issue with this patch. |
a3bc347
to
6719f43
Compare
That's great to hear, I just rebased it off the current develop (which has the latest useEditor impl) so this should be more accurate to how it actually will behave |
Looks good from my side then and can be merged. Feel free @nperez0111 |
that's right, now I see! thanks for explaining and sorry for confusion! |
Hey @nperez0111, I have experienced some weird issue after this upgrade (after I have a chat app that uses what similars to Screen.Recording.2024-09-13.at.9.01.27.AM.movI'm using React 19 RC, but it was fine previously... Do you have any clue why this is happening? Any help is much appreciated. |
Their were changes to how suggestions are triggered in this version too so it is more likely to do with that then an issue with React. Please look for an associated GitHub issue. Tracking a bug in a PR will be difficult |
Changes Overview
This PR significantly improves the performance of React NodeViews in a couple of ways:
useSyncExternalStore
to synchronize changes between React & the editor instanceWe were seeing performance problems with React NodeViews because a change to one of them would cause a re-render to all instances of node views, for an application that heavily relies on node views in React, this is expensive. This should dramatically cut down on the number of instances that have to re-render as well as making each of those re-renders much less costly.
Implementation Approach
Similar to the performance updates for Tiptap 2.5, React has it's own lifecycle for components and it really does not like when you try to force it to be synchronous (since it would prefer to batch renders together). Now we can have the best of both worlds by forcing a synchronous render on initialization, but updates afterward can be done on React's normal lifecycle (i.e. without a flushSync)
Testing Done
Verification Steps
Lots of manual testing with tons of custom react node views. Much faster than before, but hard to write tests for.
Additional Notes
Checklist
feat: Implement new feature
orchore(deps): Update dependencies
)Related Issues
#3976
#3580
#4695