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

React(Next.js)项目使用原生Editor.js渲染两个编辑器实例问题排查

问题原因

  • 初始化逻辑位置错误:EditorJS的实例化直接写在组件函数顶层,组件每次重渲染都会执行该逻辑,生成新的实例。Next.js默认开启React严格模式,开发环境下组件会强制执行两次渲染,刚好触发两次实例化,生成两个编辑器。
  • 无实例销毁逻辑:上一次渲染生成的编辑器实例没有在组件卸载/重渲染前被销毁,一直残留在DOM中。
  • 缺少客户端执行判断:EditorJS依赖浏览器API,直接在组件顶层初始化会导致服务端渲染时报window is not defined错误,和你直接访问页面报错的表现一致。

修复方案

1. 调整初始化逻辑,加销毁逻辑

将实例化逻辑放到useEffect中,通过空依赖限制仅在组件挂载时执行一次,同时增加卸载时的实例销毁逻辑,用useRef存储实例避免重复初始化:

import { useEffect, useRef } from 'react'
import EditorJS from "@editorjs/editorjs";
import css from "./removeme.module.scss" 

export default function NoteEditor(params) {
  // 存储编辑器实例
  const editorInstance = useRef(null)

  useEffect(() => {
    // 避免重复初始化
    if (editorInstance.current) return
    // 仅客户端执行
    if (typeof window === 'undefined') return

    // 初始化编辑器
    editorInstance.current = new EditorJS({
      holder: "editorjs",
    })

    // 组件卸载时销毁实例
    return () => {
      if (editorInstance.current) {
        editorInstance.current.destroy()
        editorInstance.current = null
      }
    }
  }, []) // 空依赖,仅执行一次

  return (
    <>
      <h1>新建笔记</h1>
      <div className={css["editor-area"]} id="editorjs" />
    </>
  );
}

2. 解决直接访问页面报错问题

用Next.js提供的dynamic导入,关闭编辑器组件的服务端渲染:
首先把编辑器逻辑抽为单独组件components/Editor.jsx,然后在页面中导入:

import dynamic from 'next/dynamic'

// 关闭SSR,仅客户端加载编辑器
const Editor = dynamic(() => import('../components/Editor'), {
  ssr: false,
  loading: () => <p>编辑器加载中...</p>
})

export default function NotePage() {
  return <Editor />
}

内容的提问来源于stack exchange,提问作者Shahriar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 07:36:02