Tiptap结合React-Hook-Form时useEditor依赖致焦点丢失的解决方案
React-Hook-Form 结合 Tiptap 编辑器:解决焦点丢失与状态同步问题
我在用 React-Hook-Form 的 Controller 组件控制 Tiptap 编辑器时遇到了两难问题:
- 如果把
value加入useEditor的依赖数组,输入时编辑器会频繁丢失焦点; - 要是移除
value,焦点能保留,但表单状态又没法和编辑器内容同步。
我的组件代码如下:
interface Props { value?: string; onChange?: (value: string) => void; } const TipTapEditor = ({ value, onChange }: Props) => { const editor = useEditor( { content: cleanText(value || ''), onUpdate: ({ editor }) => { onChange?.(editor.getHTML()); }, }, [value] // 移除'value'可修复焦点问题但破坏状态同步 ); }; export default TipTapEditor;
在 React-Hook-Form 的 Controller 中使用方式:
<Controller control={control} name="my-name" render={({ field: { value, onChange } }) => ( <TipTapEditor value={value} onChange={onChange} /> )} />
解决方案
核心思路是不让编辑器实例因外部 value 变化而频繁重建(这是焦点丢失的根源),改用 useEffect 监听外部值的主动更新,仅在必要时同步编辑器内容,同时保留编辑器自身更新时的表单同步逻辑。
修改后的组件代码:
import { useEffect } from 'react'; import { useEditor } from '@tiptap/react'; interface Props { value?: string; onChange?: (value: string) => void; } const TipTapEditor = ({ value, onChange }: Props) => { // 移除依赖数组中的value,确保编辑器实例只创建一次 const editor = useEditor({ content: cleanText(value || ''), onUpdate: ({ editor }) => { onChange?.(editor.getHTML()); }, }); // 监听外部value变化,仅在外部值主动更新时同步编辑器内容 useEffect(() => { if (!editor) return; const currentContent = editor.getHTML(); const targetContent = cleanText(value || ''); // 避免编辑器自身更新触发的重复同步 if (currentContent !== targetContent) { editor.commands.setContent(targetContent); } }, [editor, value]); return <div>{editor && <EditorContent editor={editor} />}</div>; }; export default TipTapEditor;
关键说明
- 保留编辑器实例稳定性:移除
useEditor依赖数组中的value,编辑器只会初始化一次,彻底解决焦点丢失问题; - 外部值同步逻辑:通过
useEffect监听外部传入的value,只有当外部值与编辑器当前内容不一致时,才调用setContent更新,避免循环触发; - 表单状态同步:编辑器自身输入时,
onUpdate依然会正常调用onChange同步表单状态,双向绑定逻辑不受影响。
内容的提问来源于stack exchange,提问作者cantCsharp
相关产品推荐
相关产品推荐

