NextJS 中的 EditorJS 无法加载插件

EditorJS in NextJS not able to load plugins

我正在尝试让 EditorJS 在 NextJS 中工作。编辑器在没有插件的情况下加载良好,唯一的段落作为块选项。但是,当我尝试通过工具道具控制台添加插件时会抛出以下警告:

editor.js?9336:2 Module Tools was skipped because of TypeError: Cannot read property 'prepare' of undefined

当我在浏览器中点击编辑器时,抛出:

Uncaught TypeError: Cannot read property 'holder' of undefined

我已经在普通的 React 应用程序中测试了编辑器插件,它们加载正常。这意味着问题出在 EditorJS 和 NextJS 插件的导入和处理中。我尝试使用 require 在 componentDidMount 钩子中导入编辑器和插件,但遇到了与 NextJS 动态导入相同的问题。尝试使用 React ref 获取组件,但发现当前 NextJS has problems with getting components' refs,尝试了建议的解决方法,但仍然没有结果。在触发 onChange 之前,编辑器的实例不可用,因此插件无法挂接到编辑器,因为 'prepare' 属性 或者整个编辑器在编辑器上的事件发生之前未定义,但是编辑器向控制台输出它已准备就绪。

我的组件代码:

import React from "react";
import dynamic from "next/dynamic";

const EditorNoSSR = dynamic(() => import("react-editor-js"), { ssr: false });
const Embed = dynamic(() => import("@editorjs/embed"), { ssr: false });
class Editor extends React.Component {
  state = {
    editorContent: {
      blocks: [
        {
          data: {
            text: "Test text",
          },
          type: "paragraph",
        },
      ],
    },
  };

  constructor(props) {
    super(props);
    this.editorRef = React.createRef();
  }

  componentDidMount() {
    console.log(this.editorRef.current);
    console.log(this.editorInstance);
  }

  onEdit(api, newData) {
    console.log(this.editorRef.current);
    console.log(this.editorInstance);

    this.setState({ editorContent: newData });
 }

  render() {
    return (
      <EditorNoSSR
        data={this.state.editorContent}
        onChange={(api, newData) => this.onEdit(api, newData)}
        tools={{ embed: Embed }}
        ref={(el) => {
          this.editorRef = el;
        }}
        instanceRef={(instance) => (this.editorInstance = instance)}
      />
    );
  }
}

export default Editor;

这个问题有什么解决办法吗?我知道 SSR 对访问 DOM 的组件的客户端呈现具有挑战性,但是使用了检查 window 对象是否未定义的条件,但是,在我的情况下它看起来不是问题。

更新:

我找到了一个解决方案,但它不是 NextJS 解决问题的方法,但是它有效。它不需要 react-editorjs,并像普通 EditorJS 一样实现为 EditorJS 实例的创建。

class Editor extends React.Component {
 constructor(props) {
   super(props);
   this.editor = null;
 }

 async componentDidMount() {
   this.initEditor();
 }

 initEditor = () => {
   const EditorJS = require("@editorjs/editorjs");
   const Header = require("@editorjs/header");
   const Embed = require("@editorjs/embed");
   const Delimiter = require("@editorjs/delimiter");
   const List = require("@editorjs/list");
   const InlineCode = require("@editorjs/inline-code");
   const Table = require("@editorjs/table");
   const Quote = require("@editorjs/quote");
   const Code = require("@editorjs/code");
   const Marker = require("@editorjs/marker");
   const Checklist = require("@editorjs/checklist");

   let content = null;
   if (this.props.data !== undefined) {
     content = this.props.data;
   }

   this.editor = new EditorJS({
     holder: "editorjs",
     logLevel: "ERROR",
     tools: {
       header: Header,
       embed: {
         class: Embed,
         config: {
           services: {
             youtube: true,
             coub: true,
           },
         },
       },
       list: List,
       inlineCode: InlineCode,
       code: Code,
       table: Table,
       quote: Quote,
       marker: Marker,
       checkList: Checklist,
       delimiter: Delimiter,
     },

     data: content,
   });
 };
 async onSave(e) {
   let data = await this.editor.saver.save();

   this.props.save(data);
 }

 render() {
   return (
     <>
       <button onClick={(e) => this.onSave(e)}>Save</button>
       <div id={"editorjs"} onChange={(e) => this.onChange(e)}></div>
     </>
   );
 }
}

此实现适用于 NextJS

如果我找到更好的解决方案,我会更新代码。

更新 2:

Rising Odegua 建议的答案有效。

您必须创建一个单独的组件,然后将所有工具导入其中:

import EditorJs from "react-editor-js";
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";

const CustomEditor = () => {

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

    return (

        <EditorJs tools={EDITOR_JS_TOOLS} />

    );
}

export default CustomEditor;

然后在您的 NextJS 页面中,使用这样的动态导入:

let CustomEditor;
if (typeof window !== "undefined") {
  CustomEditor = dynamic(() => import('../src/components/CustomEditor'));
}

并且您可以使用您的组件:

return (
  {CustomEditor && <CustomEditor />}
)

来源:https://github.com/Jungwoo-An/react-editor-js/issues/31