在Remix项目中集成Editor.js遇到问题,求可用示例
在Remix中集成Editor.js的正确实现方案
错误原因分析
window/Element is not defined:Remix服务端渲染环境中不存在浏览器的window和Element对象,直接导入Editor.js或其插件会触发报错。- ID不匹配&元素找不到:react-editor-js默认自动生成随机ID,服务端渲染生成的ID与客户端hydrate时的ID不一致,导致客户端无法找到对应的DOM容器。
解决方案步骤
- 仅在客户端加载Editor.js及其依赖,避免服务端执行浏览器专属代码。
- 手动指定固定的
holderId,确保服务端与客户端使用同一容器ID。
实现示例
方式1:动态导入+useEffect(单文件实现)
import { useEffect, useState } from "react"; export default function EditorInput() { const [ReactEditorJS, setReactEditorJS] = useState(null); const [editorTools, setEditorTools] = useState({}); useEffect(() => { // 并行加载编辑器核心与所需插件,仅在客户端执行 Promise.all([ import("react-editor-js"), import("@editorjs/link"), import("@editorjs/checklist"), ]).then(([editorModule, LinkTool, ChecklistTool]) => { setReactEditorJS(editorModule.createReactEditorJS()); setEditorTools({ link: LinkTool.default, checklist: ChecklistTool.default, }); }); }, []); // 加载完成前显示占位内容 if (!ReactEditorJS) { return <div>加载编辑器中...</div>; } return ( <ReactEditorJS holderId="fixed-editor-container" // 手动指定固定ID,消除服务端客户端ID差异 defaultValue={{ time: 1635603431943, blocks: [ { id: "sheNwCUP5A", type: "header", data: { text: "Editor.js", level: 2, }, }, { id: "12iM3lqzcm", type: "paragraph", data: { text: "Hey. Meet the new Editor. On this page you can see it in action — try to edit this text.", }, }, ], }} tools={editorTools} /> ); }
方式2:使用Remix的clientOnly组件(分离客户端代码)
- 创建客户端专属组件
app/components/EditorInput.client.js:
import { createReactEditorJS } from "react-editor-js"; import LinkTool from "@editorjs/link"; import ChecklistTool from "@editorjs/checklist"; const ReactEditorJS = createReactEditorJS(); export default function EditorInputClient() { return ( <ReactEditorJS holderId="fixed-editor-container" defaultValue={{ time: 1635603431943, blocks: [ { id: "sheNwCUP5A", type: "header", data: { text: "Editor.js", level: 2, }, }, { id: "12iM3lqzcm", type: "paragraph", data: { text: "Hey. Meet the new Editor. On this page you can see it in action — try to edit this text.", }, }, ], }} tools={{ link: LinkTool, checklist: ChecklistTool, }} /> ); }
- 在主组件中通过
clientOnly导入:
import { clientOnly } from "@remix-run/react"; // 仅在客户端渲染编辑器组件 const EditorInput = clientOnly( () => import("./EditorInput.client"), () => <div>加载编辑器中...</div> ); export default function YourPage() { return ( <div> <h1>编辑器页面</h1> <EditorInput /> </div> ); }
关键注意事项
- 所有依赖浏览器API的Editor.js插件都需要在客户端加载,不能直接在服务端导入。
- 必须手动指定
holderId,禁止使用react-editor-js的自动生成ID功能,否则会出现服务端客户端ID不匹配问题。 - 加载过程中可添加占位UI,提升用户体验。
内容的提问来源于stack exchange,提问作者Vinorcola
相关产品推荐
相关产品推荐

