react-editor-js icon indicating copy to clipboard operation
react-editor-js copied to clipboard

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

Open minhhieu1612 opened this issue 2 years ago • 16 comments

Environment

  • @editorjs/editorjs version: 2.23.2
  • react-editor-js version: 2.0.6

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,

minhhieu1612 avatar Apr 07 '22 09:04 minhhieu1612

I have the same error. Please fix it.

proteye avatar Apr 07 '22 18:04 proteye

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.

stale[bot] avatar Apr 16 '22 14:04 stale[bot]

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

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

Jungwoo-An avatar Apr 16 '22 17:04 Jungwoo-An

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()

mrspence avatar Apr 20 '22 13:04 mrspence

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

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

AlbinoGeek avatar Apr 21 '22 14:04 AlbinoGeek

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.

AdrianSchneider avatar Apr 21 '22 16:04 AdrianSchneider

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",
  }
}

AlbinoGeek avatar Apr 21 '22 16:04 AlbinoGeek

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 [email protected] solved it

StitiFatah avatar May 14 '22 10:05 StitiFatah

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: @.***>

AlbinoGeek avatar May 14 '22 12:05 AlbinoGeek

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 });

skworden avatar May 25 '22 04:05 skworden

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

bekogeko avatar Jun 10 '22 19:06 bekogeko

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 !!!

bekogeko avatar Jun 12 '22 23:06 bekogeko

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}
/>

tinwritescode avatar Oct 05 '22 12:10 tinwritescode

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

Avinash1721 avatar Oct 08 '22 16:10 Avinash1721

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

berkaygurbuz avatar Nov 12 '22 20:11 berkaygurbuz

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: @.***>

AlbinoGeek avatar Nov 13 '22 00:11 AlbinoGeek