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

如何将React Draft Wysiwyg编辑器数据从React端提交至Node.js服务端

问题原因

你遇到的[object Object]和内容不生效问题有三个直接诱因:

  • Editor组件写法存在语法错误,onEditorStateChange属性写到了自闭合标签外面,编辑器内容变化时根本不会触发状态更新
  • 定义的description state从未在编辑器内容更新时赋值,始终是初始化时的空EditorState实例,属于无效状态
  • FormData的append方法接收非字符串/Blob类型的值时,会自动调用值的toString()方法,复杂对象转换后就会输出[object Object],服务端自然无法解析

第一步:修复内容序列化问题,让服务端可正常读取

你不需要单独维护description状态,先修正Editor组件的属性绑定,直接在提交时从最新的editorState里提取内容、转成可序列化的格式即可,两种常用格式按需选择:

// 先修正Editor组件写法,去掉冗余的onEditorStateChange包装函数
return(
  <Editor  
    editorState={editorState}
    onEditorStateChange={setEditorState}
  />
)

方案1:存Draft原生结构化数据(推荐,后续支持回显编辑)

用draft-js内置的convertToRaw方法把EditorState转成可序列化的JSON对象,提交时转成JSON字符串传给服务端即可,后续回显时用convertFromRaw就能直接还原成编辑器可用的状态。
修改提交逻辑:

// 提前导入依赖
import { EditorState, convertToRaw } from 'draft-js';
// 删掉原来无效的const [description, setDescription] = useState(editorState); 代码

const handleSubmit = async (e) => {
  e.preventDefault();
  if(!file) return;

  // 从当前editorState提取内容转成可序列化结构
  const rawContent = convertToRaw(editorState.getCurrentContent());
  // 转成字符串供FormData传输
  const descriptionStr = JSON.stringify(rawContent);

  const data = new FormData();
  const filename = Date.now() + file.name;
  data.append("name", filename);
  data.append("file", file);
  data.append("username", logUser.userId);
  data.append("role", logUser.role);
  data.append("title", title);
  // 传入转换后的字符串
  data.append("description", descriptionStr);
  data.append("categories", 'Health');

  try{
    const response = await axiosPrivate.post('/v1/posts',  data,{ 
      withCredentials: true,
      headers:{authorization: `Bearer ${auth.token}`}
    })
    window.location.replace("/post/" + response.data._id);
  }catch(err){
    console.error(err);
  }
}

服务端拿到description字段后,直接调用JSON.parse就能拿到完整结构化内容,可直接存库。

方案2:直接存HTML字符串(适合不需要二次编辑、直接渲染内容的场景)

安装转换工具:npm i draftjs-to-html,提交时直接转成HTML字符串传输:

import draftToHtml from 'draftjs-to-html';

// 提交时转换
const descriptionHtml = draftToHtml(convertToRaw(editorState.getCurrentContent()));
data.append("description", descriptionHtml);

服务端拿到的就是标准HTML字符串,可直接存库、前端渲染。


第二步:实现提交时才上传编辑器内图片的逻辑

默认React Draft Wysiwyg会在插入图片时立刻触发上传,你需要先拦截默认上传逻辑,在提交时统一处理图片:

  1. 给Editor组件配置自定义图片上传回调,插入图片时只生成本地预览地址,不触发服务端请求:
import { Editor } from 'react-draft-wysiwyg';

// 自定义图片插入逻辑,仅本地预览
const uploadImageCallBack = (file) => {
  return new Promise((resolve) => {
    const reader = new FileReader();
    reader.onload = (e) => {
      resolve({ data: { link: e.target.result } });
    };
    reader.readAsDataURL(file);
  });
};

// 给Editor加工具栏配置
return(
  <Editor  
    editorState={editorState}
    onEditorStateChange={setEditorState}
    toolbar={{
      image: {
        uploadCallback: uploadImageCallBack,
        previewImage: true,
        uploadEnabled: true,
      }
    }}
  />
)
  1. 在提交逻辑里,先遍历编辑器内容提取所有图片实体,批量上传到服务端、替换本地地址为正式访问URL后,再提交最终内容:
// 放在handleSubmit里、组装FormData的逻辑之前
const contentState = editorState.getCurrentContent();
let updatedRawContent = convertToRaw(contentState);
const entityMap = updatedRawContent.entityMap;
const imageUploadTasks = [];

// 遍历所有实体筛选图片
Object.keys(entityMap).forEach(key => {
  const entity = entityMap[key];
  if (entity.type === 'IMAGE') {
    const localSrc = entity.data.link;
    // 仅本地base64/blob地址需要上传,已存在的服务端地址跳过
    if (localSrc.startsWith('data:') || localSrc.startsWith('blob:')) {
      // 把本地地址转成File对象用于上传
      const uploadTask = fetch(localSrc)
        .then(res => res.blob())
        .then(blob => {
          const imgFile = new File([blob], `editor-img-${Date.now()}.png`, { type: blob.type });
          return axiosPrivate.post('/v1/upload-img', imgFile, {
            headers: { 'Content-Type': 'multipart/form-data', authorization: `Bearer ${auth.token}` }
          })
        })
        .then(res => {
          // 替换为服务端返回的正式图片地址
          entityMap[key].data.link = res.data.url;
        });
      imageUploadTasks.push(uploadTask);
    }
  }
});

// 等所有图片上传完成、地址全部替换完毕,再生成最终内容提交
await Promise.all(imageUploadTasks);
const finalDescription = JSON.stringify(updatedRawContent);
// 把finalDescription append到FormData中即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 05:54:16