TipTap编辑器数据库内容刷新丢失及渲染延迟问题排查
问题描述
原问题
将数据库中recipe对象的ingredients字段(HTML格式,由添加食谱的TipTap编辑器生成)传入编辑食谱的TipTap编辑器时,初次加载内容可正常渲染编辑,但页面刷新后编辑器变为空白。直接传入硬编码HTML字符串(如<b>test content</b>)则无此问题。
更新后的问题
尝试用localStorage存储recipe.ingredients,或通过useEffect配合setContent方法实现持久化后,出现新问题:编辑器初始为空,需页面刷新后内容才会渲染。将console.log(recipe.ingredients)输出的HTML复制到setContent中可正常显示,但直接传入recipe.ingredients则必须刷新才生效。
解决方案
问题核心在于异步数据加载时机与编辑器初始化时机不匹配:
- 编辑器初始化时,
recipe.ingredients还未从数据库加载完成(初始为空字符串),且后续数据更新后未通知编辑器同步内容。 - 后续尝试的
useEffect仅监听editor的变化,未监听recipe.ingredients的更新,导致数据加载完成后无法触发内容设置。
修复步骤
- 在
useEffect的依赖数组中添加recipe.ingredients,确保数据更新时重新设置编辑器内容。 - 增加空值判断,避免在数据未加载完成时设置空内容。
- 移除不必要的
clearContent调用(会清空刚设置的内容)。
修复后的代码示例
const editor = useEditor({ extensions, content: '', // 初始设为空,后续通过useEffect设置 onUpdate: ({ editor }) => { const html = editor.getHTML(); setIngredients(html); console.log(html); }, }) // 监听editor和recipe.ingredients的变化 useEffect(() => { if (!editor || !recipe.ingredients) return; // 可选优化:避免重复设置相同内容 const currentHtml = editor.getHTML(); if (currentHtml !== recipe.ingredients) { editor.commands.setContent(recipe.ingredients); } }, [editor, recipe.ingredients]) // 关键:添加recipe.ingredients到依赖 if (!editor) { return null; }
原组件完整优化版
// 省略extensions定义... const TiptapIngredientsEdit = ({setIngredients}) => { const { id }= useParams(); const initialRecipeState = { id: null, title: "", description: "", recipeType: "", servingSize: null, ingredients: "", directions: "", source: "", userId: undefined }; const [recipe, setRecipe] = useState(initialRecipeState); // 获取食谱数据 const getRecipe = id => { RecipeDataService.get(id) .then(response => { setRecipe(response.data); }) .catch(e => { console.log(e); }); }; useEffect(() => { if(id) getRecipe(id); }, [id]); const editor = useEditor({ extensions, content: '', onUpdate: ({ editor }) => { const html = editor.getHTML(); setIngredients(html); } }); // 同步食谱数据到编辑器 useEffect(() => { if (!editor || !recipe.ingredients) return; editor.commands.setContent(recipe.ingredients); }, [editor, recipe.ingredients]); if (!editor) { return null; } return ( <> <Box sx={{ mb: "4px", border: 1, borderColor: 'rgb(196, 196, 196)', borderRadius: '5px'}}> <MenuBar editor={editor} /> <EditorContent editor={editor} /> </Box> </> ) } export default TiptapIngredientsEdit
关键说明
- 依赖数组中加入
recipe.ingredients,确保当数据库数据加载完成、recipe状态更新时,触发编辑器内容同步。 - 增加
!recipe.ingredients判断,避免在数据未就绪时执行无效的setContent。 - 原代码中
useEditor初始化时直接传recipe.ingredients无效,因为初始化时数据还未加载,且编辑器不会自动监听recipe的变化。
内容的提问来源于stack exchange,提问作者Lee
相关产品推荐
相关产品推荐

