React函数式组件中如何使用Draft.js编辑器处理及存储输入数据
问题修正方案
你当前代码存在3个核心错误,按以下步骤修改即可正常获取编辑器内容、存入数据库:
useState用法错误:未做数组解构,且编辑器初始值不能是空字符串,必须使用draft-js提供的EditorState.createEmpty()初始化- 组件事件绑定错误:
react-draft-wysiwyg的Editor组件不通过onChange回传状态,需要绑定专属的onEditorStateChange事件,同时必须把当前状态传入组件的editorState属性,否则编辑器是不受控状态,拿不到输入内容 - 存储逻辑缺失:draft-js内部使用Immutable结构存储内容,不能直接把EditorState对象存到数据库,需要转成通用的HTML字符串或者标准Raw JSON结构再存储
具体实现步骤
- 补充缺失的导入:如果需要转HTML存储,先安装依赖
npm i draftjs-to-html,然后在文件头部补全导入项 - 修正状态定义,为标题、选中城市、文件上传也补充对应的受控状态
- 给Editor组件正确绑定状态和变更事件
- 提交时把编辑器内容转成可存储的格式,和其他表单字段一起提交到后端
修正后的完整代码
import React, { useContext, useState } from 'react' import Modal from 'react-bootstrap/Modal'; import Button from 'react-bootstrap/Button'; import { Editor } from 'react-draft-wysiwyg'; import { EditorState, convertToRaw, convertFromRaw, ContentState } from 'draft-js'; import draftToHtml from 'draftjs-to-html'; import "react-draft-wysiwyg/dist/react-draft-wysiwyg.css"; import cityContext from "../context/cities/CityContext" export default function CreatePost(props) { const cities = useContext(cityContext); // 编辑器状态,初始化为空内容 const [editorState, setEditorState] = useState(EditorState.createEmpty()); // 其他表单字段状态 const [title, setTitle] = useState(""); const [selectedCity, setSelectedCity] = useState(""); const [uploadFile, setUploadFile] = useState(null); // 编辑器内容变更回调 const onEditorStateChange = (newEditorState) => { setEditorState(newEditorState); } // 提交表单逻辑 const handleSubmit = () => { // 方式1:转成HTML字符串,可直接存入数据库,纯展示时不需要加载编辑器 const editorContentHtml = draftToHtml(convertToRaw(editorState.getCurrentContent())); // 方式2:转成Raw JSON格式存储,后续重新加载编辑时不会丢失格式 // const editorContentRaw = JSON.stringify(convertToRaw(editorState.getCurrentContent())); // 组装所有提交数据 const submitData = { title, city: selectedCity, cover: uploadFile, content: editorContentHtml } // 此处写接口请求逻辑,将submitData传入后端存库即可 console.log("提交的数据:", submitData); props.onHide(); } return ( <div> <Modal className="text-center" {...props} size="lg" centered > <Modal.Body > <input type="text" className="form-control my-2 p-3" placeholder='Enter title of the text' value={title} onChange={(e) => setTitle(e.target.value)} /> <input type="file" className="form-control my-2 p-3" onChange={(e) => setUploadFile(e.target.files[0])} /> <select className="form-control cityField p-3 my-2" value={selectedCity} onChange={(e) => setSelectedCity(e.target.value)} > <option className='cityField' value="">--select city for the article--</option> {cities.map(cityObj => <option key={cityObj.city} value={cityObj.city} className='cityField' > {cityObj.city}</option>)} </select> <Editor className="editor" editorState={editorState} onEditorStateChange={onEditorStateChange} /> </Modal.Body> <Modal.Footer> <Button className="btn btn-danger form-control" onClick={props.onHide}>cancel</Button> <Button className="btn btn-success form-control" onClick={handleSubmit}>submit</Button> </Modal.Footer> </Modal> </div> ) }
补充说明
- 如果选择存Raw JSON格式,后续回显到编辑器时,只需要用
EditorState.createWithContent(convertFromRaw(JSON.parse(数据库存储的raw内容)))作为editorState的初始值即可,不会丢失任何格式 - 如果选择存HTML格式,前端纯展示内容时可以直接用
dangerouslySetInnerHTML={{__html: 数据库存储的html字符串}}渲染,不需要额外引入编辑器 - 编辑器的图片上传、工具栏自定义配置可以根据自身需求在Editor组件上加对应props实现
内容的提问来源于stack exchange,提问作者user16473756
相关产品推荐
相关产品推荐

