管理 React 编辑器状态
当前文档只能有一个所有者。如果应用的其他部分需要获知每一次更改,请选择受控状态;如果主要只需在保存时读取内容,请选择非受控编辑器。这些示例在 HTML 模式下使用 npm 的 React 绑定。
受控:保持本地状态为最新
"use client";
import { useState } from "react";
import { RichTextEditor } from "@richscripts/richtexteditor/react";
export default function Composer() {
const [html, setHtml] = useState("<p>Start writing...</p>");
return <RichTextEditor
value={html}
onChange={(next) => {
if (typeof next === "string") setHtml(next);
}}
/>;
}把编辑器发出的值作为您的本地编辑值。网络持久化请另行防抖,而不是有意把一个较旧的值反馈回编辑器。避免在每次保存后都用服务器规范化过的副本替换整个文档。
该绑定能区分它自己发出的值和外部替换的值,但并不能让应用的每一种转换都对选区安全。一个格式化 HTML 后再把不同内容传回的 onChange 处理函数,实际上是在要求编辑器在用户输入时替换内容。
非受控:在保存时读取当前 HTML
"use client";
import { useRef, useState } from "react";
import { RichTextEditor } from "@richscripts/richtexteditor/react";
import type { RichTextEditorReactHandle } from "@richscripts/richtexteditor/react";
export default function Draft({ initialHtml, onSave }: {
initialHtml: string;
onSave: (html: string) => void;
}) {
const editorRef = useRef<RichTextEditorReactHandle>(null);
const [ready, setReady] = useState(false);
return <>
<RichTextEditor ref={editorRef} defaultValue={initialHtml}
onReady={() => setReady(true)} />
<button type="button" disabled={!ready} onClick={() => {
if (editorRef.current?.getEditor()) {
onSave(editorRef.current.getHTMLCode());
}
}}>Save</button>
</>;
}defaultValue 用于提供文档的初始内容;它不能用来把后续更改推送到已挂载的编辑器中。ref 提供了 getHTMLCode()。就绪检查可以防止过早的保存把尚未初始化的编辑器当作空文档。
这个示例把 HTML 交给您应用的回调;它没有实现持久化、上传完成处理或保存错误恢复。如果启用了图片,请在读取最终 HTML 之前遵循上传与保存的顺序。请在服务器上验证并净化提交的内容。
安全地切换文档和处理服务器响应
- 使用稳定的文档标识。基于当前 HTML 或随机数的
key会在编辑过程中重新挂载编辑器。 - 有意使用文档 ID 作为 key,可以为另一个文档启动一个全新的编辑器。切换之前,请确认或保存有改动的草稿;重新挂载会丢弃选区和撤销历史等实例状态。
- 如果异步加载文档,请忽略或中止已不再选中的文档的响应。
- 保存时跟踪文档的修订版本。延迟到达的响应应只更新它自己那个修订版本的保存状态,而不是覆盖更新的草稿。要检测其他用户的冲突保存,需要在服务器端进行修订版本检查。
- 不要在会话中途在受控和非受控模式之间切换。请在打开文档时就选定模式。
挂载与严格模式
请使用提供的 React 包装组件,而不是在同一个宿主元素上再创建一个编辑器。如果编写自己的包装组件,请在宿主元素存在之后创建编辑器,并在清理时移除自己添加的监听器、销毁自己拥有的实例。忽略在卸载之后才完成的异步初始化。
React 严格模式在开发环境中可能会额外运行一次设置与清理。检查生命周期行为时,请保持它开启。对于 Next.js,请遵循客户端组件集成指南;渲染已保存的内容和挂载交互式编辑器是两件不同的事。
故障排查清单
- 光标跳动:检查是否有变化的 key、被重新创建的组件、重复的
setHTMLCode()调用以及被转换的受控值。 - 输入内容消失:检查来自延迟回调、保存响应和文档加载的过期值。
- 保存遗漏最后一次编辑:在提交时读取编辑器的 ref,而不是假定延迟的更改通知已经更新了 React 状态。
- 工具栏重复出现:检查是否重复初始化和清理,包括路由切换和重新打开模态框的情况。
- 大型草稿感觉卡顿:分别对 HTML 序列化、预览渲染和网络保存进行性能分析。
- 输入法输入出错:测试中文或日文的组字输入,组字期间不要改写内容,并在文本上屏后检查撤销。
下一步:逐步诊断光标跳动、安装 React 绑定,或者试试表单提交和保存与加载。
参考资料:React Strict Mode 和状态的保留与重置。