-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
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): use ref instead of state in useEditor to prevent rerenders #4856
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
@svenadlung Won't this new logic lead to memory leaks (and potentially other negative side effects)? As of this PR, whenever
deps
change, anew Editor()
is created. However, this code now onlydestroy
s theeditor
on final unmount. So it will not be callingdestroy
on any intermediaryeditor
s that are created asdeps
change.Maybe this can be fixed by moving the
destroy()
call to within the cleanup callback for theuseEffect
above that creates theeditor
. Something likeSimilarly, using
editorRef.current
as a dependency foruseEffect
for changing event handlers will not work (see explanation here https://stackoverflow.com/a/60476525/4543977). This means that if the editor changes asdeps
change, it will seemingly not be updating any of the callbacks on the new editor instance. So each neweditor
instance will not be set up correctly.I see the comment in the linked issue #4482 (comment) referencing 6984ea1 as being problematic. Seems that "Destroy editor in safe" PR #4000 was potentially the incorrect solution to its bug, and I think similarly this is a bandaid to attempt to fix a new bug that PR introduced, but unfortunately will probably introduce new bugs itself. 😕 (For what it's worth, I am still on 2.0.3 and do not experience the
[Bug]: Collaboration Cursor flickering
issue.)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.
Good eye @sjdemartini. I'm not sure exactly what
.destroy
entails but on the surface this concern appears to be valid.On the other hand, it seems possible any loose references will be dropped as they become inaccessible via any code paths - but I think for event listeners this could still be a problem, right?
As far as I know
destroy
only affects the view layer, so is it possible/safe to destroy the old editor before creating the new one? Or would that obliterate history and whatnot? It seems like it would disrupt any decoration state at the very least.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.
At the very least, the new merged implementation will be buggy in that that the event-handlers will not be reassigned whenever
deps
change foruseEditor
. So new editor instances will not function properly as dependencies change, which is most certainly a bug.But I think it's likely the negative effects will be worse than that, since
destroy
isn't called (event listeners not unassigned from stale versions of theEditor
, etc.).While this new release may fix the flickering with the collaboration cursor, I think that bug should be resolved by going back to what introduced it. It's probably worth looking at the implementation of
useEditor
prior to tiptap 2.1.0, where the flicker was not present.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.
I haven't tried
2.2.x
yet due to other blockers, but I certainly hope that memory leaks won't be introduced to accommodate features we don't use.It stands to reason that the implementation leaks, but have you done any testing to try to determine if there are indeed memory leaks @sjdemartini?
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.
I haven't tested this yet and unfortunately am unlikely to have time, as I'm swamped right now. I'm planning to stay on
v2.0.*
for now, based on the new issues (flickering with the collaboration extension in 2.1, and the new problems here around listeners and/or memory problems in 2.2).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.
Good catch.
For reference, there won't be any memory leak if you keep the dependency array empty.
I would remove the
deps
array altogether because I don't think anyone would intentionally want to re-create the editor.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.
Sure, but that's my whole point: if you actually do need to use the dependency array, this new code will not work properly. The dependency array exists for a reason and has since the early days of Tiptap, as there are legitimate use-cases that require recreating the editor when dependencies change (vs just using methods on the editor itself or something). For instance, you may need to do so if your list of
extensions
changes.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.
I believe your assumption has been right @sjdemartini. I've noticed a breaking change going from 2.2.1 (prior to this change) and 2.2.2 (the release of this change). If you call
editor.commands.focus()
from theonCreate
handler it will work in 2.2.1 and not in 2.2.2. Likely because the handlers haven't been reassigned after a new editor instance was created.Here's two codesandboxes comparing the two versions:
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.
@samvantoever can you check whether adding a
setTimeout
around your focus call resolves the issue? If so, I would think that suggests race condition rather than handler assignment issue.