React:收集子组件数组状态值并更新对象后保存到PouchDB
解决多Tiptap子组件统一保存到PouchDB的方案
子组件改造:用useImperativeHandle暴露数据接口
要在每个包含Tiptap Editor的子组件里,通过useImperativeHandle暴露获取编辑器JSON数据的方法,让父组件能直接调用:
import { useImperativeHandle, forwardRef, useEffect } from 'react'; import { useEditor, EditorContent } from '@tiptap/react'; const TableEditor = forwardRef(({ registerRef, unregisterRef, initialContent }, ref) => { const editor = useEditor({ extensions: [], // 你的编辑器扩展配置 content: initialContent || '', }); // 暴露获取编辑器数据的方法 useImperativeHandle(ref, () => ({ getEditorData: () => editor?.getJSON() || {}, })); // 挂载/卸载时维护父组件的ref数组 useEffect(() => { registerRef(ref); return () => unregisterRef(ref); }, [registerRef, unregisterRef, ref]); return ( <div className="table-editor"> {editor && <EditorContent editor={editor} />} </div> ); }); TableEditor.displayName = 'TableEditor'; export default TableEditor;
父组件:维护数组Ref并实现统一保存
父组件用useRef创建数组存储所有子组件引用,点击统一保存按钮时遍历数组收集数据,再处理PouchDB的保存逻辑:
import { useRef } from 'react'; import TableEditor from './TableEditor'; import PouchDB from 'pouchdb'; const db = new PouchDB('your-database-name'); const ParentComponent = () => { const editorRefs = useRef([]); // 注册子组件ref const registerEditorRef = (ref) => { if (ref && !editorRefs.current.includes(ref)) { editorRefs.current.push(ref); } }; // 注销子组件ref(防止内存泄漏) const unregisterEditorRef = (ref) => { editorRefs.current = editorRefs.current.filter(item => item !== ref); }; // 统一保存逻辑 const handleSaveAll = async () => { // 收集所有子编辑器的数据 const sections = editorRefs.current.map(ref => ref.getEditorData()); try { // 先获取目标文档的最新版本(不存在则创建新文档) let targetDoc; try { targetDoc = await db.get('your-document-id'); } catch (err) { targetDoc = { _id: 'your-document-id', sections: [] }; } // 更新sections数组(按需替换或合并) targetDoc.sections = sections; // 写入PouchDB await db.put(targetDoc); console.log('所有表格数据保存成功'); } catch (err) { console.error('保存失败:', err); } }; return ( <div> {/* 渲染多个子编辑器组件 */} <TableEditor initialContent="<table>...</table>" registerRef={registerEditorRef} unregisterRef={unregisterEditorRef} /> <TableEditor initialContent="<table>...</table>" registerRef={registerEditorRef} unregisterRef={unregisterEditorRef} /> {/* 统一保存按钮 */} <button onClick={handleSaveAll}>保存所有表格</button> </div> ); }; export default ParentComponent;
关键注意点
- 数组Ref维护:通过子组件的
useEffect完成注册与注销,确保父组件的ref数组始终与当前挂载的子组件同步,避免内存泄漏。 - PouchDB更新逻辑:必须先获取文档的最新版本再执行
put操作,否则会出现仅更新_rev但实际数据未写入的情况,这也是你之前遇到问题的核心原因。 - 数据合并策略:如果不需要完全替换
sections数组,可以给每个子组件添加唯一标识(如id或index),对应更新数组中的指定项,避免覆盖原有数据。
内容的提问来源于stack exchange,提问作者William Chorski
相关产品推荐
相关产品推荐

