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

react-draft-wysiwyg搭配Formik如何实现后端数据回显与编辑同步

React-draft-wysiwyg 配合 Formik 回显与状态同步修复方案

核心问题梳理

  • 缺少后端返回富文本到EditorState的转换逻辑,后端返回的HTML/raw结构不能直接传入编辑器
  • 富文本状态没有和Formik做双向绑定,修改内容无法同步到表单提交数据中
  • 现有useEffect中的异步函数未执行,setDetails调用逻辑错误,触发不了状态更新
  • 直接修改details对象不符合React不可变更新规则,状态变更无法被监听到

实现逻辑说明

  1. 回显逻辑:拿到后端返回的富文本内容后,先转成draft-js认可的EditorState格式,再赋值给编辑器
  2. 状态同步:编辑器内容修改时,同步将EditorState更新到Formik的对应字段中,不需要额外维护独立的EditorState状态
  3. 提交逻辑:提交时直接从Formik字段中取EditorState转成HTML传给后端即可

完整修正代码

import draftToHtml from "draftjs-to-html";
import { Editor } from "react-draft-wysiwyg";
import { EditorState, convertFromRaw, convertToRaw, ContentState } from "draft-js";
// 如果后端返回的是HTML格式富文本,需要先安装导入html-to-draftjs
import htmlToDraft from 'html-to-draftjs';
import { Formik, Form } from 'formik';
import { useContext, useState, useEffect } from 'react';

const Sampleform=()=>{
  const { ContextData } = useContext(SomeContext);
  const[loading,setLoading]=useState(false);
  // 存储后端返回的原始详情数据
  const [details, setDetails] = useState(null);

  // 拉取后端数据的逻辑
  const getNewDetails = async () => {
    setLoading(true);
    try {
      // 替换为实际接口请求
      const res = await fetch('/your/api/endpoint');
      const backendData = await res.json();
      setDetails(backendData);
    } catch (error) {
      console.log('接口请求失败', error);
    } finally {
      setLoading(false);
    }
  }

  // 依赖ContextData变化触发数据拉取
  useEffect(() => {
    if (ContextData) {
      getNewDetails();
    }
  }, [ContextData]);

  // 转换后端返回的富文本为EditorState格式
  const convertBackendContentToEditorState = (backendContent) => {
    if (!backendContent) return EditorState.createEmpty();
    try {
      // 情况1:后端返回的是draft-js原生raw JSON格式
      if (typeof backendContent === 'object' && backendContent.blocks) {
        return EditorState.createWithContent(convertFromRaw(backendContent));
      }
      // 情况2:后端返回的是HTML字符串格式
      if (typeof backendContent === 'string') {
        const contentBlock = htmlToDraft(backendContent);
        if (contentBlock) {
          const contentState = ContentState.createFromBlockArray(contentBlock.contentBlocks, contentBlock.entityMap);
          return EditorState.createWithContent(contentState);
        }
      }
      return EditorState.createEmpty();
    } catch (err) {
      console.error('富文本格式转换失败', err);
      return EditorState.createEmpty();
    }
  }

  return(
    <Formik
      enableReinitialize={true}
      // 初始值用details数据转换后的值,details更新后会自动刷新初始值
      initialValues={{
        date: details?.date || null,
        body: convertBackendContentToEditorState(details?.body),
      }}
      validationSchema={validationSchema}
      onSubmit={(values, { setSubmitting }) => {
        // 提交时将EditorState转成HTML传给后端
        const submitData = {
          date: values.date,
          body: draftToHtml(convertToRaw(values.body.getCurrentContent()))
        }
        // 后续提交逻辑自行实现
        console.log('待提交数据', submitData);
        setSubmitting(false);
      }}
    >
      {({
        values,
        handleBlur,
        setFieldValue,
        handleSubmit,
        isSubmitting,
        errors,
        touched,
      }) => (
        <Form>
          {/* 日期等其他表单元素正常实现即可 */}
          <div>
            <Editor
              editorState={values.body}
              wrapperClassName="demo-wrapper"
              editorClassName="demo-editor"
              // 内容变化时同步更新到Formik对应字段
              onEditorStateChange={(newState) => setFieldValue('body', newState)}
              onBlur={() => handleBlur('body')}
              toolbar={{
                options: ["inline", "list", "link", "remove"],
                inline: {
                  options: ["bold", "italic", "underline"],
                  bold: { className: "bordered-option-classname" },
                  italic: { className: "bordered-option-classname" },
                  underline: { className: "bordered-option-classname" },
                },
              }}
              spellCheck={true}
            />
          </div>     
        </Form>
      )}
    </Formik>
  );
};

export default Sampleform;

注意事项

  • 如果后端返回的是HTML格式,需要先安装依赖:npm i html-to-draftjs
  • 不需要额外维护独立的EditorState状态,所有状态统一交给Formik管理,避免多状态不同步问题
  • enableReinitialize={true}配置保证details更新后Formik初始值会自动刷新

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.17 18:45:04