draft-js 是 Facebook 开源的 React 富文本编辑器核心框架,提供了底层的状态管理和渲染机制。react-draft-wysiwyg 则是基于 draft-js 构建的成品组件库,封装了工具栏、样式和常用功能。两者并非直接的竞争关系,而是“底层引擎”与“上层封装”的关系。选择 draft-js 意味着你需要自己搭建编辑器界面;选择 react-draft-wysiwyg 则意味着你直接使用一套现成的界面方案。
在 React 生态中构建富文本编辑器时,draft-js 和 react-draft-wysiwyg 是两个经常同时出现的名字。但很多开发者容易混淆它们的定位。简单来说,draft-js 是发动机,而 react-draft-wysiwyg 是组装好的整车。理解这一层关系,对于架构选型至关重要。
draft-js 是一个核心框架。
// draft-js: 需要手动搭建编辑器结构
import { Editor, EditorState } from 'draft-js';
function MyEditor() {
const [editorState, setEditorState] = useState(
EditorState.createEmpty()
);
return (
<div className="editor-container">
{/* 你需要自己写工具栏 */}
<div className="toolbar">/* 自定义按钮 */</div>
{/* 核心编辑器区域 */}
<Editor
editorState={editorState}
onChange={setEditorState}
/>
</div>
);
}
react-draft-wysiwyg 是一个封装组件。
draft-js 开发,内置了工具栏、链接弹窗、图片上传等 UI。// react-draft-wysiwyg: 直接使用封装好的组件
import { Editor } from 'react-draft-wysiwyg';
function MyEditor() {
const [editorState, setEditorState] = useState(
EditorState.createEmpty()
);
return (
<Editor
editorState={editorState}
onEditorStateChange={setEditorState}
toolbar={{ /* 配置工具栏选项 */ }}
wrapperClassName="demo-wrapper"
editorClassName="demo-editor"
/>
);
}
draft-js 要求你手动实现所有交互。
RichUtils.toggleInlineStyle。// draft-js: 手动处理样式切换
const handleToggle = (style) => {
onChange(
RichUtils.toggleInlineStyle(editorState, style)
);
};
<button
onClick={() => handleToggle('BOLD')}
className={editorState.getCurrentInlineStyle().has('BOLD') ? 'active' : ''}
>
B
</button>
react-draft-wysiwyg 通过配置对象控制工具栏。
// react-draft-wysiwyg: 配置化工具栏
<Editor
editorState={editorState}
onEditorStateChange={setEditorState}
toolbar={{
inline: { inDropdown: false },
options: ['inline', 'blockType', 'list'],
inline: { options: ['BOLD', 'ITALIC', 'UNDERLINE'] }
}}
/>
两者都依赖 draft-js 的核心数据模型,所以在数据处理上是相同的。
ContentState 来存储文本内容。Immutable.js 数据结构(这是 draft-js 的特点)。// 两者通用:导出 HTML 内容
import { convertToHTML } from 'draft-convert';
import { ContentState } from 'draft-js';
const contentState = editorState.getCurrentContent();
const html = convertToHTML(contentState);
// 结果:'<p>Hello <strong>World</strong></p>'
// 两者通用:从 HTML 导入内容
import { convertFromHTML } from 'draft-convert';
import { ContentState, EditorState } from 'draft-js';
const blocksFromHTML = convertFromHTML(htmlContent);
const state = ContentState.createFromBlockArray(
blocksFromHTML.contentBlocks,
blocksFromHTML.entityMap
);
const editorState = EditorState.createWithContent(state);
这是架构决策中最需要警惕的部分。
draft-js 处于维护模式。
// 风险提示:draft-js 依赖 Immutable.js
// 这增加了包体积,且 API 学习曲线较陡
import { Map, List } from 'immutable';
// 现代编辑器多已转向普通 JavaScript 对象
react-draft-wysiwyg 依赖上游状态。
draft-js 的架构。// 风险提示:封装库可能滞后于 React 新版本
// 例如 React 18 的并发特性可能未完全适配
import { Editor } from 'react-draft-wysiwyg';
// 需测试在 StrictMode 下的行为
尽管一个是核心一个是封装,它们共享许多底层特性。
// 两者通用:获取当前块类型
const selection = editorState.getSelection();
const currentBlock = contentState.getBlockForKey(selection.getStartKey());
const type = currentBlock.getType(); // 例如 'unordered-list-item'
draft-js 有 draft-js-plugins 生态。react-draft-wysiwyg 继承了这个能力。// 两者通用:使用插件创建编辑器状态
import createImagePlugin from 'draft-js-image-plugin';
const imagePlugin = createImagePlugin();
const editorState = EditorState.createEmpty(pluginsDecorator);
blockRendererFn 控制特定块的 UI。// 两者通用:自定义块渲染
function blockRendererFn(contentBlock) {
if (contentBlock.getType() === 'atomic') {
return {
component: MyAtomicComponent,
editable: false,
};
}
}
| 特性 | draft-js | react-draft-wysiwyg |
|---|---|---|
| 定位 | 🧠 核心引擎框架 | 📦 成品 UI 组件库 |
| 工具栏 | 🛠️ 需完全手写实现 | ⚙️ 配置化生成 |
| 开发成本 | 📈 高(需处理底层逻辑) | 📉 低(开箱即用) |
| 定制能力 | 🚀 无限定制 | 🔒 受限于封装逻辑 |
| 依赖关系 | 💠 无依赖(核心) | 🔗 依赖 draft-js |
| 维护状态 | ⚠️ 维护模式(更新慢) | ⚠️ 跟随上游(更新慢) |
draft-js 像是一套精密的机械零件 🧩——适合那些需要自己组装引擎、对性能和控制力有极致要求的团队。但你要清楚,这套零件的设计图纸已经几年没有大更新了。
react-draft-wysiwyg 像是一辆组装好的家用车 🚗——适合需要立刻上路、功能标准且不需要改装引擎的团队。它能帮你省下几个月的开发时间,但你要接受它的配置限制。
最终建议:如果是维护旧项目,两者配合依然稳定可靠。如果是全新项目,建议认真评估 Slate.js 或 TipTap。它们提供了更现代的 API 设计(不依赖 Immutable.js),社区活跃度更高,更适合未来 3-5 年的技术演进。但如果必须在二者中选,追求效率选封装,追求控制选核心。
选择 react-draft-wysiwyg 如果你需要快速上线一个标准的富文本编辑器,且不需要深度定制工具栏逻辑。它适合中小型项目或后台管理系统,能大幅减少样板代码,但需接受其依赖 draft-js 的技术限制及维护现状。
选择 draft-js 如果你的团队需要完全定制编辑器界面,或者现有的封装无法满足特定的业务交互需求。它适合有足够开发资源去维护底层逻辑的大型项目,但要注意其生态更新较慢,适合需要深度控制渲染行为的场景。
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.