来自数据库的数据不会保留在 tiptap 编辑器内容中

Data from database does not persist in tiptap editor content

提问人:Lee 提问时间:9/30/2023 最后编辑:Lee 更新时间:10/1/2023 访问量:168

问:

更新

从我收到的关于这个问题的一些建议中,我现在发现,无论是将我的 recipe.ingredients 设置为本地存储,还是将 setContent 与 useEffect 一起使用,如下所示,确实在 tiptap 编辑器中设置了一个持久值。但是,使用这两种方法中的任何一种都会导致不同的问题,即在我刷新页面之前,内容不会呈现。这意味着编辑器是空的,除非页面由于某种延迟而刷新。就像下面描述的问题一样,如果我输入一个html值,我就没有这个问题。例如,如果我控制台.log(recipe.ingredients),然后将控制台中的html剪切并粘贴到编辑器上的内容中,则一切正常,但是如果我尝试传递recipe.ingredients,则在我刷新页面之前它不会呈现。由于当我输入用引号括起来的 html 字符串时它起作用,因此我尝试将值括在引号中,然后像这样传递它:

`'`+ recipe.ingredients + `'` 

这只会导致我最初的问题中描述的相同问题,但显示了引号。

总而言之,这在页面刷新之前不起作用:

const editor = useEditor({

    extensions,
        content:'',
        onUpdate: ({ editor }) => {
      const html = editor.getHTML();
                setIngredients(html);
        editor.commands.clearContent()
      console.log(html);
    },
  })

  useEffect(() => {
    if (!editor) {
      return undefined
    }

    editor.commands.setContent(recipe.ingredients)
  }, [editor])

  if (!editor) {
    return null
  } 

但是像这样写出的 Recipe.Ingredients 的 HTML 值工作正常:


const editor = useEditor({

    extensions,
        content:'',
        onUpdate: ({ editor }) => {
          const html = editor.getHTML();
          setIngredients(html);
      console.log(html);
    },
  })

  useEffect(() => {
    if (!editor) {
      return undefined
    }

    editor.commands.setContent('<ul><li><p>mac</p></li><li> 
      <p>cheese</p></li></ul>')
    }, [editor])

    if (!editor) {
    return null
  } 

结束更新原题:

当我将数据从数据库中的字段传递到 TipTap 编辑器的内容时,我在刷新时丢失了 TipTap 编辑器(基于 ProseMirror)的内容。

我的目标是从数据库中的 recipe 对象中获取 ingredients 字段,并将其传递给 tiptap 编辑器。数据采用 html 格式,是在我的“添加食谱”表单中使用 TipTap 编辑器创建的。我希望数据在这个新的TipTap编辑器中显示并可编辑,这将是用户“编辑食谱”表单的一部分。请注意,我相信这与这里提出的问题相同:如何持久化数据,使其不会在 TipTap 编辑器中被删除?但是,该问题没有提供任何示例代码,因此我在问题中提供了更多上下文。

这是我当前的代码,我将 recipe.ingredients 数据传递给 TipTap 编辑器内容:

// define your extension array
const extensions = [
  Color.configure({ types: [TextStyle.name, ListItem.name] }),
  TextStyle.configure({ types: [ListItem.name] }),
  StarterKit.configure({
    bulletList: {
      keepMarks: true,
      keepAttributes: false, // TODO : Making this as `false` becase marks are not preserved when I try to preserve attrs, awaiting a bit of help
    },
    orderedList: {
      keepMarks: true,
      keepAttributes: false, // TODO : Making this as `false` becase marks are not preserved when I try to preserve attrs, awaiting a bit of help
    }
  }),
  // Placeholder.configure({
  //   placeholder: 'Ingredients',
  // }),
  Underline, 
  TextAlign.configure({
    types: ['heading', 'paragraph'], 
    alignments: ['left', 'right'],
    defaultAlignment: 'left',
  })
]

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);

     //get recipe
     const getRecipe = id => {
    RecipeDataService.get(id)
    .then(response => {
      setRecipe(response.data);
      console.log(response.data.ingredients);
    })
    .catch(e => {
      console.log(e);
    });
  };
  
  useEffect(() => {
    if(id)
    getRecipe(id);
  }, [id]);

  const editor = useEditor({
    extensions,
    content: recipe.ingredients,
    onUpdate: ({ editor }) => {
      const html = editor.getHTML();
      setIngredients(html);
      console.log(html);
    }
  })

  return (
  <>
    <Box sx={{ mb: "4px", border: 1, borderColor: 'rgb(196, 196, 196)', borderRadius: '5px'}}>
      <MenuBar editor={editor} />
      <EditorContent editor={editor} /> 
    </Box>
  </>
  )
}

export default TiptapIngredientsEdit

成分最初按预期从 html 呈现,并可以根据需要进行编辑:

screenshot of results showing data in tiptap editor

但是在页面刷新后,编辑器内容变为空白:

screenshot of blank editor contents

如果我提供一个像这样的内容的html字符串,我不会遇到同样的问题,所以将数据从数据库传递到内容似乎是一个问题:

const editor = useEditor({

    extensions,
    content: '<b>test content</b>',
    onUpdate: ({ editor }) => {
      const html = editor.getHTML();
      setIngredients(html);
      console.log(html);
    }
  })
ReactJS 编辑器 Tiptap 散文镜像

评论


答:

1赞 I_am_prince 9/30/2023 #1

您需要在初始化时进行编辑,并且您的内容为空,我们需要直接将内容设置为编辑器对象。ingredientsingredientsuseEditor

因此,根据解决方案,只需将成分设置为使用命令即可。您可以在此处查看详细信息。https://tiptap.dev/api/commands/set-contenteditorsetContent

代码需要添加

useEffect(() => {
     editor.commands.setContent(recipe.ingredients)
}, [recipe]);

您更新的代码

// define your extension array
const extensions = [
  Color.configure({ types: [TextStyle.name, ListItem.name] }),
  TextStyle.configure({ types: [ListItem.name] }),
  StarterKit.configure({
    bulletList: {
      keepMarks: true,
      keepAttributes: false, // TODO : Making this as `false` becase marks are not preserved when I try to preserve attrs, awaiting a bit of help
    },
    orderedList: {
      keepMarks: true,
      keepAttributes: false, // TODO : Making this as `false` becase marks are not preserved when I try to preserve attrs, awaiting a bit of help
    }
  }),
  // Placeholder.configure({
  //   placeholder: 'Ingredients',
  // }),
  Underline, 
  TextAlign.configure({
    types: ['heading', 'paragraph'], 
    alignments: ['left', 'right'],
    defaultAlignment: 'left',
  })
]

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);

     //get recipe
     const getRecipe = id => {
    RecipeDataService.get(id)
    .then(response => {
      setRecipe(response.data);
      console.log(response.data.ingredients);
    })
    .catch(e => {
      console.log(e);
    });
  };
  
  useEffect(() => {
    if(id)
    getRecipe(id);
  }, [id]);

  useEffect(() => {
     editor.commands.setContent(recipe.ingredients)
  }, [recipe]);

  const editor = useEditor({
    extensions,
    content: recipe.ingredients,
    onUpdate: ({ editor }) => {
      const html = editor.getHTML();
      setIngredients(html);
      console.log(html);
    }
  })

  return (
  <>
    <Box sx={{ mb: "4px", border: 1, borderColor: 'rgb(196, 196, 196)', borderRadius: '5px'}}>
      <MenuBar editor={editor} />
      <EditorContent editor={editor} /> 
    </Box>
  </>
  )
}

export default TiptapIngredientsEdit

谢谢

评论

0赞 Lee 9/30/2023
感谢您的帮助。我按照您的建议尝试了,但我收到一条错误消息:无法读取 null 的属性(读取“commands”) TypeError:无法读取 null 的属性(读取“commands”)
0赞 Lee 10/1/2023
我想出了如何避免错误的方法,如我对上述问题的更新所示。它并没有完全解决我的问题,因为现在在我刷新页面而不是相反之前没有任何显示,但感谢您为我指明了一个有用的方向。
0赞 I_am_prince 10/1/2023
你能根据你的代码创建一个发送箱并发送到这里,这样我就可以正确解析。
0赞 Lee 10/1/2023
非常感谢您提供更多帮助!我终于通过将您建议的函数放在我的编辑器中的函数中并添加一行来检查编辑器是否存在,从而使一切正常工作:reddit.com/r/react/comments/xr6c2h/...。我会将最终版本粘贴到上面的问题中。我真的很感谢你对这个让我发疯的问题的帮助。
1赞 Lee 10/1/2023 #2

这是最终版本,根据 I_am_prince 的答案,我可以解决所有这些问题,但进行了一些更改以使其在我的代码中正常工作:

    const editor = useEditor({

    extensions,
        content: '',
        onUpdate: ({ editor }) => {
      const html = editor.getHTML();
                setIngredients(html);
      console.log(html);
    },
    contentEditable: "true"
  })

  useEffect(() => {
    if (editor && !editor.isDestroyed) editor.commands.setContent(recipe.ingredients);
  }, [recipe.ingredients]);

  return (
  <>
    <Box sx={{ mb: "4px", border: 1, borderColor: 'rgb(196, 196, 196)', borderRadius: '5px'}}>
      <MenuBar editor={editor} />
      <EditorContent editor={editor} /> 
     
    </Box>
  </>
  )
}