You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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的更新,导致数据加载完成后无法触发内容设置。

修复步骤

  1. 在useEffect的依赖数组中添加recipe.ingredients,确保数据更新时重新设置编辑器内容。
  2. 增加空值判断,避免在数据未加载完成时设置空内容。
  3. 移除不必要的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 16:48:25