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

Error: flushSync was called from inside a lifecycle method in <PureEditorContent> #3580

Closed
1 of 2 tasks
diegoulloao opened this issue Dec 28, 2022 · 35 comments · Fixed by #3781
Closed
1 of 2 tasks

Error: flushSync was called from inside a lifecycle method in <PureEditorContent> #3580

diegoulloao opened this issue Dec 28, 2022 · 35 comments · Fixed by #3781
Labels
Type: Bug The issue or pullrequest is related to a bug

Comments

@diegoulloao
Copy link

diegoulloao commented Dec 28, 2022

What’s the bug you are facing?

The component import { EditorContent } from "@tiptap/react" is crashing for some reason.

I'm getting the following error in console:

Uncaught Error: flushSync was called from inside a lifecycle method. It cannot be called when React is already rendering.
    at flushSync (react-dom.development.js:21917:1)
    at PureEditorContent.maybeFlushSync (EditorContent.tsx:82:1)
    at PureEditorContent.removeRenderer (EditorContent.tsx:100:1)
    at ReactRenderer.destroy (ReactRenderer.tsx:93:1)
    at ReactNodeView.destroy (ReactNodeViewRenderer.tsx:173:1)
...

More specifically here:

The above error occurred in the <PureEditorContent> component:
    in PureEditorContent
    in PureEditorContent (at TipTap.js:154)
    in div (at TipTap.js:145)
...

Reduced code:

const TipTap = ({ editor, ...props }) => {
  return (
    <div className="tip-tap-editor-container text-editor">
      <EditorContent className="tip-tap-editor-content mt-5" editor={editor} />
    </div>
  )
}

If I remove the <EditorContent> the app doesn't crash.

Not sure if this bug is only related to our implementation.
Anyway, any help, clue or information is welcome in order to fix this issue which is urgent.

Which browser was this experienced in? Are any special extensions installed?

Google Chrome
Version 108.0.5359.124 (Official Build) (arm64)

macOs ventura 13.1

How can we reproduce the bug on our side?

Not sure.

Can you provide a CodeSandbox?

No response

What did you expect to happen?

Not crashing.

Anything to add? (optional)

Tip-tap package versions:

{
    "@tiptap/extension-color": "^2.0.0-beta.209",
    "@tiptap/extension-highlight": "^2.0.0-beta.209",
    "@tiptap/extension-image": "^2.0.0-beta.209",
    "@tiptap/extension-link": "^2.0.0-beta.209",
    "@tiptap/extension-placeholder": "^2.0.0-beta.209",
    "@tiptap/extension-text-style": "^2.0.0-beta.209",
    "@tiptap/extension-underline": "^2.0.0-beta.209",
    "@tiptap/react": "^2.0.0-beta.209",
    "@tiptap/starter-kit": "^2.0.0-beta.209",
}

React version: 16.13.1
Node version: v14.19.1

You can find the entire log here: tiptap.log


Note: my app depends of this node version only

Did you update your dependencies?

  • Yes, I’ve updated my dependencies to use the latest version of all packages.

Are you sponsoring us?

  • Yes, I’m a sponsor. 💖
@diegoulloao diegoulloao added the Type: Bug The issue or pullrequest is related to a bug label Dec 28, 2022
@HiDeoo
Copy link

HiDeoo commented Dec 28, 2022

I'm also experiencing the same errors after an update from 2.0.0-beta.202 to 2.0.0-beta.209.

From a real quick search, it looks like #3331 may be the only changes related to this error between the 2 versions.

@kolyagora
Copy link

There is a PR addressing this issue: #3533

@diegoulloao
Copy link
Author

diegoulloao commented Dec 30, 2022

PR #3533 should fix this issue then.

@JosephHalter
Copy link

+1

@arpit016
Copy link

@bdbch I am still experiencing this bug, I am using tiptap v2.0.3. Any fix or workaround?, It mainly crashes the app when the editor is unmounting or when the user is navigating away from the page containing editor. Can we reopen this issue?

@Hideman85
Copy link

I'm having this as well with 2.0.3

@bdbch bdbch reopened this Jun 29, 2023
@bdbch
Copy link
Contributor

bdbch commented Jun 29, 2023

Could you create a replicatable sandbox for us? @Hideman85 @arpit016 so we can verify the issue still exist?

@rbruels
Copy link

rbruels commented Aug 4, 2023

@bdbch Still occurs in 2.0.4 -- here's a code sandbox: https://codesandbox.io/s/github/rbruels/tiptap-3580-sandbox

@bdbch
Copy link
Contributor

bdbch commented Aug 5, 2023

Moved back to the backlog

@benjackwhite
Copy link

For what it's worth, testing locally for us and removing the flushSync call all-together of course stopped the error. Interestingly though through testing a bunch of our custom Nodes and navigating across multiple dynamically re-initialised editors, nothing else seemed to be off.

I assume there is a good reason for using flushSync but it isn't super obvious from the code alone what that is 🤔

@Nantris
Copy link
Contributor

Nantris commented Aug 12, 2023

Fwiw I've never seen this occur over hundreds of hours building our TipTap/React editor (but mostly using 2.1.0-rc.*.) I wonder what the cause could be.

@rbruels
Copy link

rbruels commented Aug 12, 2023

@slapbox Feel free to check my code sandbox — see if you can reproduce too. Maybe you’ll have an idea why it’s happening

@Nantris
Copy link
Contributor

Nantris commented Aug 12, 2023

Ah I didn't realize the issue was specific to ReactNodeViewRenderer rather than useEditor/EditorContent. We don't use ReactNodeViewRenderer, so I guess that explains never seeing it.

Relink to the relevant code sandbox for convenience: https://codesandbox.io/s/github/rbruels/tiptap-3580-sandbox

@totorofly
Copy link

In my situation, I was experiencing poor performance and lag as the number of lines in a Paragraph node with a NodeView increased. This significantly impacted the user experience during text input. However, when I changed the maybeFlushSync(fn: () => void) method from:

if (this.initialized) {
  flushSync(fn);
} else {
  fn();
}

to:

if (this.initialized) {
  fn();
} else {
  fn();
}

The lag and performance issues were resolved. I am just not sure what potential risks this change might introduce.

@philipaarseth
Copy link

philipaarseth commented Sep 3, 2023

Experienced this after updating from 2.0.0-beta.220 to 2.1.7. Seems to have been caused by using setContent inside a useEffect. Moving the initialize editor content to useEditor({ content: content seem to have fixed it for me.

offending code inside useEffect:

editor?.commands?.setContent({
  type: "doc",
  content: doc?.content || []
});

@essmahr
Copy link

essmahr commented Sep 13, 2023

We are running into this as well for the same reason as @philipaarseth (imperatively updating content in a useEffect).

Since we depend on updating content within an effect like this, I found that wrapping the offending setContent inside a queueMicrotask also makes the error go away... but watching this issue for a proper fix 😄

@Aldredcz
Copy link

FYI: We also struggled with this, but after a bump from 2.0.0-beta.209 to 2.1.13 the issue disappeared 🎉

@ccreusat
Copy link

Still experiencing the error with 2.1.13 or 2.1.16

@semanticist21
Copy link

Putting logic inside queueMicrotask(..) solved perfectly!
Thanks.

@fridaystreet
Copy link

fridaystreet commented Apr 25, 2024

still getting this in 2.3.0

@rfdrake27
Copy link

Same here. Still not fixed in 2.30 and my console is just getting flooded in the flushSync errors.

@mhogryd
Copy link

mhogryd commented Jun 25, 2024

I'm having this problem as well with 2.4.0.

I tried implementing a basic example from the TipTap docs and got the crash as well, the counter here: https://tiptap.dev/docs/editor/guide/node-views/react

Adding the queueMicrotask fix here back in as a patch fixes the issue for me: aa43898

@nperez0111
Copy link
Contributor

Should be resolved with tiptap 2.5 since we no longer have to flushSync anymore

@Aslam97
Copy link

Aslam97 commented Aug 7, 2024

@nperez0111 still facing the same issue with 2.5.9

Warning: flushSync was called from inside a lifecycle method. React cannot flush when React is already rendering. Consider moving this call to a scheduler task or micro task.

@rfdrake27
Copy link

I can confirm it's still present on 2.5.9 as well.

@nperez0111
Copy link
Contributor

You are using a React nodeview? Or is this with useEditor?

I must've read the issue incorrectly. Tiptap 2.5 fixes useEditor, node views will be resolved with: #5273

@Nantris
Copy link
Contributor

Nantris commented Aug 8, 2024

I don't see this exact issue anymore but I do sometimes still see: Warning: Attempted to synchronously unmount a root while React was already rendering. React cannot finish unmounting the root until the current render has completed, which may lead to a race condition PureEditorContent

With useEditor.

I think this only occurs when swapping the editor out for a new one (eg user changes the selected content) but we're not breaking any rules of React or of TipTap as far as I can tell, so I wouldn't expect this.

@nperez0111
Copy link
Contributor

PureEditorContent is to do with React nodeviews:

maybeFlushSync(fn: () => void) {
// Avoid calling flushSync until the editor is initialized.
// Initialization happens during the componentDidMount or componentDidUpdate
// lifecycle methods, and React doesn't allow calling flushSync from inside
// a lifecycle method.
if (this.initialized) {
flushSync(fn)
} else {
fn()
}
}

So not yet resolved, but will be with #5273

@Nantris
Copy link
Contributor

Nantris commented Aug 8, 2024

Ah apologies. I was pretty sure I'd seen it on a page where we used none, but I'm probably mistaken about that.

@nperez0111
Copy link
Contributor

This should now be resolved with 2.6.0

@rajatkulkarni95
Copy link

rajatkulkarni95 commented Aug 25, 2024

@nperez0111 I think it still isn't fixed. I'm on the latest 2.6.2 patch, and here's an example.

One note has node views component (the purple text blocks you see), while the other doesn't. When the note loads, you can see the warning in the console, but not for the other note.

    "@tiptap/pm": "^2.6.2",
    "@tiptap/react": "^2.6.2",

And this is my useEditor block

  const editor = useEditor(
    {
      extensions: editorExtensions,
      editorProps: memoizedEditorProps,
      autofocus,
      onUpdate: debouncedHandleSave,
      shouldRerenderOnTransaction: false,
      immediatelyRender: true,
      editable: true,
    },
    [memoizedEditorProps, autofocus]
  );
Screen.Recording.2024-08-25.at.12.10.13.mov

@nperez0111
Copy link
Contributor

@nperez0111 I think it still isn't fixed. I'm on the latest 2.6.2 patch, and here's an example.

@rajatkulkarni95 So node views should only flushSync now when the editor is already initialized

if (this.editor.isInitialized) {
// On first render, we need to flush the render synchronously
// Renders afterwards can be async, but this fixes a cursor positioning issue
flushSync(() => {
this.render()
})
} else {

Do note that this is only a warning & React does the right thing anyway (because at worst your focus cannot be moved into the node view properly which is the only reason we are trying to flush it synchronously).

Given what you were doing here I would expect it to only render once. I'd be interested if you logged in the component that called useEditor whether it was re-rendering multiple times.

@rajatkulkarni95
Copy link

Given what you were doing here I would expect it to only render once. I'd be interested if you logged in the component that called useEditor whether it was re-rendering multiple times.

Here's the logs. Both cause the same amount of renders it seems.

Do note that this is only a warning & React does the right thing anyway
Yeah till it won't have adverse side effects, I'm not really concerned.

Screen.Recording.2024-08-26.at.19.38.40.mov

@nperez0111
Copy link
Contributor

Here's the logs. Both cause the same amount of renders it seems.

That's a lot of renders... I would consider wrapping the component that renders the editor to be memoized to be shielded from all of these renders.

useEditor wherever possible will try to re-use the editor instance, but it can be garbage collected if the editors are far enough apart. If collected, this would destroy the instance & force a remount after recreating. All that to say, I would totally expect this to happen with how many times it is rendered. React does not really give us much room here for a solution. We need it to be synchronous & it isn't, we don't have a way to know whether React is already rendering something else. So our hands are tied here, but again, not an actual issue.

So I think it is safe to say, if you don't recreate the editor a bunch of times really quickly this already is solved. Tons of people already have this in prod from my understanding

@rajatkulkarni95
Copy link

Here's the logs. Both cause the same amount of renders it seems.

That's a lot of renders... I would consider wrapping the component that renders the editor to be memoized to be shielded from all of these renders.

useEditor wherever possible will try to re-use the editor instance, but it can be garbage collected if the editors are far enough apart. If collected, this would destroy the instance & force a remount after recreating. All that to say, I would totally expect this to happen with how many times it is rendered. React does not really give us much room here for a solution. We need it to be synchronous & it isn't, we don't have a way to know whether React is already rendering something else. So our hands are tied here, but again, not an actual issue.

So I think it is safe to say, if you don't recreate the editor a bunch of times really quickly this already is solved. Tons of people already have this in prod from my understanding

Yeah it's rendering 15 times, which seems a lot. So I have an Editor.tsx component that has a bunch of states and stuff, and that calls my custom useCustomEditor hook which calls useEditor from tiptap.

I think some re-renders are unavoidable, since some of the extensions require some data from state, but I feel 15 can be brought down.

Will check, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Bug The issue or pullrequest is related to a bug
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.