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

React+TypeScript中EditorJS调用destroy方法报错问题求助

EditorJS在React+TS中卸载时destroy is not a function问题解决

问题原因

你当前的代码中,editorInstance是useEffect内部的局部变量,存在两个核心问题:

  1. 闭包引用失效:当initialData变化触发组件重新渲染时,新的useEffect会创建新的editorInstance,而旧的清理函数捕获的是旧作用域里的实例——此时旧实例对应的DOM已经被新实例占用,内部状态已被破坏,调用destroy时就会出现方法不存在的异常。
  2. 严格模式双重执行:React开发环境默认开启严格模式,会双重执行useEffect,导致创建两个EditorJS实例。第一个实例的DOM被第二个覆盖后,其destroy方法已无法正常工作。

而使用useRef保存实例的核心原因是:useRef的.current属性在组件整个生命周期内是稳定的单一引用,不会随组件重新渲染创建新变量,能始终获取到最新的有效EditorJS实例。

修复后的代码

// Import necessary modules
import React, { useRef, useEffect } from "react";
import EditorJS, { OutputData } from "@editorjs/editorjs";
import { Tools } from "./Tools";
import "./styles.css";

interface EditorProps {
  initialData?: OutputData; // Optional initial data in JSON format
}

// Define the Editor component
const Editor: React.FC<EditorProps> = ({ initialData }) => {
  // 用useRef存储EditorJS实例,保证引用全局稳定
  const editorRef = useRef<EditorJS | null>(null);

  // Function to handle saving the editor content
  const handleSave = async () => {
    console.log("saving content...");
    if (editorRef.current) {
      const data = await editorRef.current.save();
      // 这里实现你的保存逻辑
      console.log(data);
    }
  };

  // Initialize the editor when the component mounts or initialData changes
  useEffect(() => {
    // 若已有实例,先销毁再创建新的,避免DOM冲突
    if (editorRef.current) {
      editorRef.current.destroy();
      editorRef.current = null;
    }

    // Initialize EditorJS
    const editorInstance = new EditorJS({
      holder: "editorjs",
      tools: Tools,
      initialData: initialData || undefined,
    });

    editorInstance.isReady
      .then(() => console.log("Editor.js is ready to work!"))
      .catch((err) => console.error(err));

    editorRef.current = editorInstance;

    // Cleanup function to destroy the editor when the component unmounts or effect re-runs
    return () => {
      if (editorRef.current) {
        console.log("destroying editor instance...");
        editorRef.current.destroy();
        editorRef.current = null;
      }
    };
  }, [initialData]);

  return (
    <div className="editor-container">
      <div id="editorjs" style={{ minHeight: "300px" }}></div>
      <button className="save-button" onClick={handleSave}>
        Save
      </button>
    </div>
  );
};

export default Editor;

关键修改说明

  1. 用useRef存储实例:避免了局部变量的闭包作用域问题,确保任何时候都能获取到最新的有效实例。
  2. effect重执行时先销毁旧实例:当initialData变化时,先清理旧实例再创建新的,防止多个实例争抢同一个DOM元素。
  3. 清理后清空ref引用:销毁实例后重置editorRef.current,避免保留无效引用导致后续异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 12:07:06