react-draft-wysiwyg搭配Formik如何实现后端数据回显与编辑同步
React-draft-wysiwyg 配合 Formik 回显与状态同步修复方案
核心问题梳理
- 缺少后端返回富文本到EditorState的转换逻辑,后端返回的HTML/raw结构不能直接传入编辑器
- 富文本状态没有和Formik做双向绑定,修改内容无法同步到表单提交数据中
- 现有useEffect中的异步函数未执行,setDetails调用逻辑错误,触发不了状态更新
- 直接修改details对象不符合React不可变更新规则,状态变更无法被监听到
实现逻辑说明
- 回显逻辑:拿到后端返回的富文本内容后,先转成draft-js认可的EditorState格式,再赋值给编辑器
- 状态同步:编辑器内容修改时,同步将EditorState更新到Formik的对应字段中,不需要额外维护独立的EditorState状态
- 提交逻辑:提交时直接从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
相关产品推荐
相关产品推荐

