我正在尝试让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 在获取组件的 refs 方面存在问题,尝试了建议的解决方法,但仍然没有结果。在触发 onChange 之前,编辑器的实例不可用,因此插件无法挂接到编辑器,因为该“准备”属性或整个编辑器在编辑器上的事件发生之前未定义,但编辑器输出到控制台它已经准备好了。
我的组件代码:
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 的组件的客户端渲染具有挑战性,但是使用了条件来检查窗口对象是否未定义,但是,在我的情况下它看起来不是问题。
更新:
我找到了一个解决方案,但它不是解决问题的 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 提出的答案是有效的。