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

draftjs编辑器中按退格键删除图片时如何同步删除数据库对应资源

DraftJS编辑器删除图片时同步清理数据库资源的实现方案

核心实现逻辑

  • 给图片绑定唯一资源标识:图片上传到后端存储成功后,除了返回图片访问URL,后端需要同步返回该资源的全局唯一ID,将ID和URL共同存入DraftJS自定义图片原子块的entity数据中,避免仅依赖URL判断出现重复URL误删的问题。创建图片entity的示例代码如下:
    const imageEntityKey = Entity.create(
      'CUSTOM_IMAGE',
      'IMMUTABLE',
      { url: 'https://your-cdn.com/xxx.jpg', resourceId: 'img_123456abcdef' }
    )
    
  • 监听编辑器内容变更:通过DraftJS原生提供的onChange回调,每次内容更新时拿到最新的EditorState实例。
  • 对比图片ID差集:每次内容变更时,分别提取上一次编辑器状态和当前最新状态中所有图片的resourceId,二者的差集即为用户刚刚删除的图片资源ID。
  • 防抖调用删除接口:拿到被删除的资源ID列表后,加300~500ms的防抖调用后端资源删除接口,避免用户频繁操作时产生大量无效请求,同时兼容用户误删后马上撤销的场景,避免不必要的资源删除。

边缘情况兜底处理

  • 适配撤销/重做操作:每次onChange触发时同步更新存储的历史图片ID列表,无需额外处理撤销重做逻辑,差集计算逻辑会自动适配状态回退的场景,若用户撤销删除操作,对应ID会重新出现在最新ID列表中,不会触发删除。
  • 临时资源标记:未正式提交的草稿关联的图片资源需要打临时标记,只有用户确认删除草稿、或草稿超过7天未编辑时再清理对应资源,避免用户编辑中途退出后重新进入草稿出现图片丢失的问题。
  • 后台定时清理:作为前端监听逻辑的兜底,后端可每日定时扫描所有未被任何正式内容、有效草稿关联的图片资源,统一清理,避免极端场景下的垃圾数据残留。

核心实现代码示例

import { useState, useRef } from 'react';
import { Editor, EditorState, convertToRaw } from 'draft-js';
import debounce from 'lodash/debounce';

const DraftEditor = () => {
  const [editorState, setEditorState] = useState(() => EditorState.createEmpty());
  // 存储上一次编辑器内容中的图片资源ID列表
  const lastImgIds = useRef([]);

  // 提取指定EditorState中所有图片的资源ID
  const getAllImgResourceIds = (state) => {
    const contentState = state.getCurrentContent();
    const rawBlocks = convertToRaw(contentState).blocks;
    const idList = [];
    rawBlocks.forEach(block => {
      block.entityRanges.forEach(range => {
        const entity = contentState.getEntity(range.key);
        if (entity.getType() === 'CUSTOM_IMAGE') {
          idList.push(entity.getData().resourceId);
        }
      })
    })
    return idList;
  };

  // 防抖调用删除接口
  const deleteImageResources = debounce(async (deletedIds) => {
    await fetch('/api/image/delete', {
      method: 'POST',
      body: JSON.stringify({ resourceIds: deletedIds })
    })
  }, 400);

  const handleEditorChange = (newState) => {
    setEditorState(newState);
    const newImgIds = getAllImgResourceIds(newState);
    // 计算被删除的资源ID
    const deletedIds = lastImgIds.current.filter(id => !newImgIds.includes(id));
    if (deletedIds.length) {
      deleteImageResources(deletedIds);
    }
    // 更新存储的ID列表
    lastImgIds.current = newImgIds;
  };

  return <Editor editorState={editorState} onChange={handleEditorChange} />
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 06:06:03