react-draft-wysiwyg 和 react-quill 都是 React 生态中流行的富文本编辑器(WYSIWYG)解决方案,但它们的底层引擎和设计理念截然不同。react-draft-wysiwyg 基于 Facebook 的 Draft.js 构建,提供高度可定制的 React 组件化体验,但受限于底层库的归档状态。react-quill 则是成熟的 Quill 编辑器的 React 封装,拥有强大的富文本处理能力和稳定的 Delta 数据模型,适合需要复杂格式支持的生产环境。
在 React 项目中集成富文本编辑器是一个常见的架构决策。react-draft-wysiwyg 和 react-quill 曾经是两个最热门的选择,但它们的现状和适用场景已经发生了巨大变化。作为架构师,我们需要透过 API 表面,深入到底层引擎、数据模型和维护状态来评估风险。
这是两者之间最大的区别,也是决定性的架构风险。
react-draft-wysiwyg 依赖于 Draft.js。Facebook 已经正式归档(Archived)了 Draft.js 仓库,不再接受新功能或主要维护。这意味着底层引擎已经停止演进。
// react-draft-wysiwyg 依赖链
// react-draft-wysiwyg -> draft-js (Archived by Meta)
// 风险:底层不再修复安全漏洞或兼容新 React 版本
react-quill 依赖于 Quill.js。Quill 在经历了长期的 2.0 开发后,近期发布了正式版本,社区依然活跃,底层引擎仍在更新。
// react-quill 依赖链
// react-quill -> quill (Active Maintenance)
// 优势:底层持续修复 bug 并支持新特性
💡 架构建议:除非你正在维护一个无法迁移的旧系统,否则 不要 在新项目中使用
react-draft-wysiwyg。底层库的死亡意味着你的编辑器功能将被冻结在时间中。
编辑器如何存储和序列化数据,直接影响你的后端设计和数据迁移成本。
react-draft-wysiwyg 使用 Draft.js 的 ContentState。这是一种基于 Immutable.js 的复杂 JSON 结构。
// react-draft-wysiwyg: 导出原始 JSON
import { convertToRaw } from 'draft-js';
const rawContent = convertToRaw(editorState.getCurrentContent());
// 输出: { blocks: [...], entityMap: {...} }
// 缺点:结构复杂,难以直接转换为 HTML,依赖特定库解析
react-quill 使用 Delta 格式。这是一种简洁的操作数组,也可以轻松导出为 HTML。
// react-quill: 导出 Delta 或 HTML
const delta = quillRef.current.getDelta();
// 输出: { ops: [{ insert: "Hello" }, { insert: "World", attributes: { bold: true } }] }
const html = quillRef.current.root.innerHTML;
// 输出: "<p>Hello<strong>World</strong></p>"
// 优势:Delta 适合协作编辑,HTML 适合直接存储展示
当默认工具栏无法满足需求时,两者的扩展方式体现了不同的设计哲学。
react-draft-wysiwyg 允许你直接使用 React 组件来渲染自定义块。这对 React 开发者来说非常直观。
// react-draft-wysiwyg: 自定义块渲染
function MyCustomBlock(props) {
return <div className="custom-box">{props.children}</div>;
}
const editorProps = {
blockRendererFn: (block) => {
if (block.getType() === 'atomic') {
return {
component: MyCustomBlock,
editable: false,
};
}
}
};
<Editor editorState={state} onEditorStateChange={setState} {...editorProps} />
react-quill 使用 Quill 的 Blot 系统。这需要在 Quill 的注册表中定义,不能直接当作普通 React 组件使用,集成难度较高。
// react-quill: 自定义 Blot (需在 Quill 实例外注册)
import Quill from 'quill';
const BlockEmbed = Quill.import('blots/block/embed');
class MyEmbed extends BlockEmbed {
static create(value) {
let node = super.create();
node.setAttribute('data-id', value);
return node;
}
}
Quill.register(MyEmbed);
// 在 React 组件中使用
<ReactQuill modules={{ toolbar: [['my-embed', 'custom']] }} />
在大型表单或高频输入场景下,编辑器的渲染行为至关重要。
react-draft-wysiwyg 强依赖于 editorState 的受控模式。每次击键都会触发 React 状态更新,如果组件树过深,可能导致输入延迟。
// react-draft-wysiwyg: 典型的受控模式
const [editorState, setEditorState] = useState(EditorState.createEmpty());
// 每次 onChange 都会重新渲染整个 Editor 组件
<Editor
editorState={editorState}
onEditorStateChange={setEditorState}
/>
react-quill 支持非受控模式(通过 defaultValue)或混合模式,减少不必要的 React 渲染循环。它更多地依赖内部 DOM 管理。
// react-quill: 推荐的非受控或半受控模式
const quillRef = useRef(null);
// 仅在需要时获取内容,减少 React 重渲染
<ReactQuill
theme="snow"
defaultValue="<p>Initial content</p>"
ref={quillRef}
/>
// 提交时获取
const content = quillRef.current.editor.root.innerHTML;
尽管底层不同,两者都努力适应 React 的开发习惯。
两者都允许通过配置对象自定义工具栏。
// react-draft-wysiwyg
const toolbar = {
options: ['inline', 'blockType', 'list'],
inline: { options: ['bold', 'italic'] }
};
<Editor toolbar={toolbar} />
// react-quill
const modules = {
toolbar: [
[{ 'header': [1, 2, false] }],
['bold', 'italic']
]
};
<ReactQuill modules={modules} />
两者都需要引入 CSS 文件,且都支持通过类名覆盖默认样式。
/* 两者都需要全局 CSS 支持 */
@import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css';
@import 'react-quill/dist/quill.snow.css';
/* 自定义样式覆盖 */
.DraftEditor-root { font-family: 'CustomFont'; }
.ql-editor { font-family: 'CustomFont'; }
| 特性 | react-draft-wysiwyg | react-quill |
|---|---|---|
| 底层引擎 | Draft.js (已归档 ❌) | Quill.js (活跃 ✅) |
| 数据格式 | Immutable ContentState (JSON) | Delta (JSON) 或 HTML |
| 自定义扩展 | 原生 React 组件 (简单) | Quill Blots (较复杂) |
| React 集成 | 深度受控 (可能性能敏感) | 支持非受控 (性能较好) |
| 长期风险 | 高 (依赖已死) | 低 (社区维护) |
| 适用场景 | 遗留项目维护 | 新项目、复杂富文本需求 |
react-draft-wysiwyg 曾经是一个优秀的库,它让 Draft.js 变得易用。但如今,它就像一艘依赖已沉没引擎的船。在 2024 年及以后,选择它意味着你主动承担了底层库停止维护的风险。仅当你在维护一个无法重构的旧系统时,才继续使用它。
react-quill 是目前更务实的选择。虽然它的自定义扩展机制(Blots)不如纯 React 组件直观,但它提供了一个功能完整、经过生产验证的编辑引擎。对于大多数需要富文本功能的企业级应用,它是更安全的基础设施。
最终思考:富文本编辑器是前端最复杂的组件之一。如果可能,评估是否需要完整的 WYSIWYG。很多时候,基于 Markdown 的编辑器(如 react-markdown + Textarea)或更现代的 Headless 编辑器(如 Tiptap)可能是更好的架构选择,它们能提供更长的生命周期和更好的开发体验。
仅建议在维护基于 Draft.js 的遗留项目时选择此包。由于底层依赖 Draft.js 已被官方归档且不再维护,新项目使用它会面临长期的技术债务和安全风险。如果你的团队已经深度绑定 Draft.js 的数据结构且短期内无法迁移,它可以作为过渡方案,否则应避免在新架构中引入。
适合大多数需要稳定富文本编辑功能的新项目,特别是需要处理复杂格式(如表格、特定样式)的场景。虽然 Quill 的自定义扩展(Blots)学习曲线较陡,但其社区活跃且底层引擎持续更新。如果你需要更现代化的 React 集成体验,也可以考虑基于 ProseMirror 或 Tiptap 的替代方案,但在本对比中,它是更稳健的选择。
A Wysiwyg editor built using ReactJS and DraftJS libraries. Demo Page.

The package can be installed from npm react-draft-wysiwyg
$ npm install --save react-draft-wysiwyg draft-js
Editor can be used as simple React Component:
import { Editor } from "react-draft-wysiwyg";
import "react-draft-wysiwyg/dist/react-draft-wysiwyg.css";
<Editor
editorState={editorState}
toolbarClassName="toolbarClassName"
wrapperClassName="wrapperClassName"
editorClassName="editorClassName"
onEditorStateChange={this.onEditorStateChange}
/>;
For more documentation check here.
For discussions join public channel #rd_wysiwyg in DraftJS Slack Organization.
You can fund project at Patreon.
Original motivation and sponsorship for this work came from iPaoo. I am thankful to them for allowing the Editor to be open-sourced.
MIT.