Jungwoo-An / react-editor-js

⚛️📝The unofficial editor-js component for React
https://codesandbox.io/s/react-editor-js-v2-34bfl
MIT License
940 stars 77 forks source link

Runtime Error: this._editorJS.destroy is not a function #190

Open minhhieu1612 opened 2 years ago

minhhieu1612 commented 2 years ago

Environment

Describe

I currently using next.js version 12.1.4. And the error occurs after the ClientEditorCore instance initial success as you can see below: image

Also, there are two editors components mount on the page: image

Editor.tsx file:

import React, { useEffect, useRef, useState } from "react";
import { EditorBlockPropsType } from "./index.type";
import { createReactEditorJS } from "react-editor-js";
import { ClientEditorCore } from "@react-editor-js/client/dist/client/src/client-editor-core";

const ReactEditorJS = createReactEditorJS();
const REACT_EDITOR_HOLDER_ID = "ssrHolder";

const EditorBlock = ({ content }: EditorBlockPropsType) => {
  let editorInstance;
  const [tools, setTools] = useState<any>();
  const initialValue = content || {
    time: 1635603431943,
    blocks: [
      {
        id: "sheNwCUP5A",
        type: "header",
        data: {
          text: "Editor.js",
          level: 2,
        },
      },
    ],
  };

  useEffect(() => {
    (async () => {
      const importedTools = await import("./editorTools");
      setTools(importedTools.EDITOR_JS_TOOLS);
    })();
    // console.log(EditorJS);
  }, []);

  if (!tools) {
    return <>Loading....</>;
  }

  return (
    <ReactEditorJS
      holder={REACT_EDITOR_HOLDER_ID}
      instanceRef={(instance: any) => (editorInstance = instance)}
      tools={tools}
      defaultValue={initialValue}
      placeholder="write something here..."
      onInitialize={(currentEditor: ClientEditorCore) =>
        console.log(currentEditor)
      }
    />
  );
};

export default EditorBlock;

editorTools.ts file:

import Embed from "@editorjs/embed";
import Table from "@editorjs/table";
import List from "@editorjs/list";
import Warning from "@editorjs/warning";
import Code from "@editorjs/code";
import LinkTool from "@editorjs/link";
import Image from "@editorjs/image";
import Raw from "@editorjs/raw";
import Header from "@editorjs/header";
import Quote from "@editorjs/quote";
import Marker from "@editorjs/marker";
import CheckList from "@editorjs/checklist";
import Delimiter from "@editorjs/delimiter";
import InlineCode from "@editorjs/inline-code";
import SimpleImage from "@editorjs/simple-image";

export const EDITOR_JS_TOOLS = {
  embed: Embed,
  table: Table,
  marker: Marker,
  list: List,
  warning: Warning,
  code: Code,
  linkTool: LinkTool,
  image: Image,
  raw: Raw,
  header: Header,
  quote: Quote,
  checklist: CheckList,
  delimiter: Delimiter,
  inlineCode: InlineCode,
  simpleImage: SimpleImage,
};

My github repo Thank for support me,

proteye commented 2 years ago

I have the same error. Please fix it.

stale[bot] commented 2 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

Jungwoo-An commented 2 years ago

I'm sorry for the late response. I'll fix it.

If you want to contribute this repo, feel free to create pull request.

mrspence commented 2 years ago

Suspect this is caused when the react component is created and destroyed before Editor JS is fully loaded (Editor JS has a pending promise on editorJS.isReady that resolves once fully loaded).

This means if you call _editorJS.destroy() before the underlying Editor JS is fully loaded, an error is thrown... https://github.com/codex-team/editor.js/issues/919#issuecomment-574332951

Temporary fix is don't create / destroy your react editor js component within ~3 seconds, suspect actual fix for react-editor-js is await _editorJS.isReady and then _editorJS.destroy()

AlbinoGeek commented 2 years ago

Yeah... this results in the package failing in NextJS.

Specifically, even with SSR disabled, two EditorJS components render, and this error is thrown.

AdrianSchneider commented 2 years ago

We just went through this as well: two components and a destroy error.

In our case, it was only broken in React 18. Downgrading to 17 fixed it for us.

AlbinoGeek commented 2 years ago

We just went through this as well: two components and a destroy error.

In our case, it was only broken in React 18. Downgrading to 17 fixed it for us.

Incredible! This at least lets me try and develop with this.

Temporary Workaround

# Downgrade to React 17 (and matching react-* packages)
# works for NextJS as well;
npx yarn add react@^17 react-dom@^17
# or
yarn add react@^17 react-dom@^17
# or
npm install react@^17 react-dom@^17

Result in package.json

{
  "dependencies": {
    "react": "^17",
    "react-dom": "^17",
  }
}
StitiFatah commented 2 years ago

Are you guys sure it's a react version problem ? Just got this error with .focus after updating react-editor-js to 2.0.6 and downgrading to react-editor-js@2.0.5 solved it

AlbinoGeek commented 2 years ago

To be fair, this is not the only extension that explodes when you give it react 18. One of the biggest changes, is the rendering mode. ReactDOM absolutely floods the console telling you that render is deprecated, this breaks a lot of extensions.

Pinning react and reactDOM 17 has worked great for me in the one application I use this extension.

On Sat., May 14, 2022, 3:01 a.m. StitiFatah, @.***> wrote:

Are you guys sure it's a react version problem ? Just got this error with .focus after updating react-editor-js to 2.0.6 and downgrading to @.*** solved it

— Reply to this email directly, view it on GitHub https://github.com/Jungwoo-An/react-editor-js/issues/190#issuecomment-1126683532, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAOSNPJ65YQR5AUPUOLE5GLVJ52ZHANCNFSM5SYYDRVA . You are receiving this because you commented.Message ID: @.***>

skworden commented 2 years ago

I'm using React 18 and Next 12, and this plugin was duplicating the editor, and throwing destroy is not a function error.

I fixed it by removing this plugin and using the default editorjs.

import EditorJS from "@editorjs/editorjs";
import { useEffect, useId, useRef } from "react";

const Editor = () => {
  const holder = useId();
  const editor = useRef<EditorJS | null>(null);

  useEffect(() => {
    if (!editor.current) {
      editor.current = new EditorJS({
        data: { blocks: [] },
        holder,
        tools: {},
      });
    }
    return () => {
      if (editor.current && editor.current.destroy) {
        editor.current.destroy();
      }
    };
  }, []);

  return <div id={holder} ref={editor}></div>;
};
export default Editor;

If you use Next.js, you can import the component to work with SSR.

const Editor = dynamic(() => import("path/to/editor"), { ssr: false });
bekogeko commented 2 years ago

in next.js its giving an error about usage of useRef image second error is same

bekogeko commented 2 years ago

i realised its about strict mode and double invoking when its double invoked (its also means enviroment is in strict mode) its creates double instance and because of that one of them creates this error. Becase one of them is still null !!!

tinwritescode commented 1 year ago

Work for me:

const [tools, setTools] = useState<any>()

useEffect(() => {
  ;(async () => {
    const importedTools = await import('../components/editor-config')
    setTools(importedTools.EDITOR_JS_TOOLS)
  })()
}, [])
<EditorJs
  onInitialize={(editor: any) => {
    editorRef.current = editor
  }}
  placeholder="Notes"
  minHeight={100}
  onChange={(value: any) => {
    setFieldValue('note', value)
  }}
  tools={tools}
/>
Avinash1721 commented 1 year ago

This issue is coming because with react 18 page is rendered twice. To avoid this, turn off the strict mode in next.config.js

https://nextjs.org/docs/api-reference/next.config.js/react-strict-mode https://reactjs.org/docs/strict-mode.html#ensuring-reusable-state

berkaygurbuz commented 1 year ago

I'm using React 18 and Next 12, and this plugin was duplicating the editor, and throwing destroy is not a function error.

I fixed it by removing this plugin and using the default editorjs.

import EditorJS from "@editorjs/editorjs";
import { useEffect, useId, useRef } from "react";

const Editor = () => {
  const holder = useId();
  const editor = useRef<EditorJS | null>(null);

  useEffect(() => {
    if (!editor.current) {
      editor.current = new EditorJS({
        data: { blocks: [] },
        holder,
        tools: {},
      });
    }
    return () => {
      if (editor.current && editor.current.destroy) {
        editor.current.destroy();
      }
    };
  }, []);

  return <div id={holder} ref={editor}></div>;
};
export default Editor;

If you use Next.js, you can import the component to work with SSR.

const Editor = dynamic(() => import("path/to/editor"), { ssr: false });

When I use your workaround, I couldn't write anything in input

AlbinoGeek commented 1 year ago

Not supporting react 18 will become less and less of an option as time goes on. I understand that they are deprecating the virtual dom, frankly, good riddance. You can also force a react 18 app to work with react 17, but when react 19 comes around, that all goes out the window.

What doesn't make a whole lot of sense to me is that it's created twice and react 18, that is the inverse of what I would expect the deprecation of virtual dom to result in

On Sat., Nov. 12, 2022, 12:55 p.m. Berkay Gürbüz, @.***> wrote:

I'm using React 18 and Next 12, and this plugin was duplicating the editor, and throwing destroy is not a function error.

I fixed it by removing this plugin and using the default editorjs.

import EditorJS from @.***/editorjs"; import { useEffect, useId, useRef } from "react";

const Editor = () => { const holder = useId(); const editor = useRef<EditorJS | null>(null);

useEffect(() => { if (!editor.current) { editor.current = new EditorJS({ data: { blocks: [] }, holder, tools: {}, }); } return () => { if (editor.current && editor.current.destroy) { editor.current.destroy(); } }; }, []);

return

; }; export default Editor;

If you use Next.js, you can import the component to work with SSR.

const Editor = dynamic(() => import("path/to/editor"), { ssr: false });

When I use your workaround, I couldn't write anything in input

— Reply to this email directly, view it on GitHub https://github.com/Jungwoo-An/react-editor-js/issues/190#issuecomment-1312570095, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAOSNPOYAJN4FY65MGVI6G3WH774JANCNFSM5SYYDRVA . You are receiving this because you commented.Message ID: @.***>