You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Remix项目中集成Editor.js遇到问题,求可用示例

在Remix中集成Editor.js的正确实现方案

错误原因分析

  1. window/Element is not defined:Remix服务端渲染环境中不存在浏览器的window和Element对象,直接导入Editor.js或其插件会触发报错。
  2. 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组件(分离客户端代码)

  1. 创建客户端专属组件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,
      }}
    />
  );
}
  1. 在主组件中通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 01:45:08