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
相关产品推荐
相关产品推荐

