保存到数据库

现在你已经学会了如何向 Slate 编辑器添加功能的基本知识,你可能想要知道如何保存你已经编辑过的内容,这样你就可以在之后返回应用程序并且加载它。

在这篇指南中,我们会像你展示如何添加逻辑,以便将你在 Slate 中编辑的内容保存到一个数据库中并在随后读取它。

让我们从一个基本的编辑器开始:

  1. const App = () => {
  2. const editor = useMemo(() => withReact(createEditor()), [])
  3. const [value, setValue] = useState([
  4. {
  5. type: 'paragraph',
  6. children: [{ text: '段落中的一段文本。' }],
  7. },
  8. ])
  9. return (
  10. <Slate editor={editor} value={value} onChange={value => setValue(value)}>
  11. <Editable />
  12. </Slate>
  13. )
  14. }

它将会渲染一个基本的 Slate 编辑器在页面上,随着你输入内容会发生变化。但是如果你刷新页面,所有内容都将回到一开始的时候 — 什么都没有被保存!

我们需要做的是保存你在某个地方做的改变。对于这个例子来说,虽然我们仅仅使用了 Local Storage ,但是这会给你怎么保存数据带来灵感。

所以,在我们的 onChange 事件处理函数中,我们需要保存 value

  1. const App = () => {
  2. const editor = useMemo(() => withReact(createEditor()), [])
  3. const [value, setValue] = useState([
  4. {
  5. type: 'paragraph',
  6. children: [{ text: '段落中的一段文本。' }],
  7. },
  8. ])
  9. return (
  10. <Slate
  11. editor={editor}
  12. value={value}
  13. selection={selection}
  14. onChange={value => {
  15. setValue(value)
  16. // 在 Local Storage 里保存值。
  17. const content = JSON.stringify(value)
  18. localStorage.setItem('content', content)
  19. }}
  20. >
  21. <Editable />
  22. </Slate>
  23. )
  24. }

现在无论何时你编辑页面,如果你查看 Local Storage,你应该会看到 content 的值已经被改变。

但是,如果你刷新页面,还是和之前一样,什么都不存在了。这是因为我们需要确保初始值是从同一个 Local Storage 读取的。就像这样:

  1. const App = () => {
  2. const editor = useMemo(() => withReact(createEditor()), [])
  3. // 如果 Local Storage 存在值,用它来更新初始值。
  4. const [value, setValue] = useState(
  5. JSON.parse(localStorage.getItem('content')) || [
  6. {
  7. type: 'paragraph',
  8. children: [{ text: '段落中的一段文本。' }],
  9. },
  10. ]
  11. )
  12. return (
  13. <Slate
  14. editor={editor}
  15. value={value}
  16. onChange={value => {
  17. setValue(value)
  18. const content = JSON.stringify(value)
  19. localStorage.setItem('content', content)
  20. }}
  21. >
  22. <Editable />
  23. </Slate>
  24. )
  25. }

现在你应该能够保存刷新之间的变化了!

成功了 — 你已经有一个 JSON 对象在你的数据库了。

但是如果你想要保存的数据格式不是 JSON 呢? 没问题,只要你用不同的方式去序列化你的值就好了。比如说你想要保存纯文本而不是 JSON,我们可以编写一些逻辑来序列化和反序列化纯文本的值。

  1. // 从 Slate 导入 `Node` 帮助函数接口。
  2. import { Node } from 'slate'
  3. // 定义一个参数为 `value` 返回值是纯文本的序列化函数。
  4. const serialize = value => {
  5. return (
  6. value
  7. // 返回这个 value 中每一个段落中的子节点的字符串内容。
  8. .map(n => Node.string(n))
  9. // 用换行符(用换行符来区分段落)来连接他们。
  10. .join('\n')
  11. )
  12. }
  13. // 定义一个参数是字符串返回值是 `value` 的反序列化函数
  14. const deserialize = string => {
  15. // 分隔字符串,返回一个包含value的child数组。
  16. return string.split('\n').map(line => {
  17. return {
  18. children: [{ text: line }],
  19. }
  20. })
  21. }
  22. const App = () => {
  23. const editor = useMemo(() => withReact(createEditor()), [])
  24. // 使用我们的反序列化函数来从 Local Storage 中读取数据。
  25. const [value, setValue] = useState(
  26. deserialize(localStorage.getItem('content')) || ''
  27. )
  28. return (
  29. <Slate
  30. editor={editor}
  31. value={value}
  32. onChange={value => {
  33. setValue(value)
  34. // 序列化 `value` 并将产生的字符串保存到 Local Storage。
  35. localStorage.setItem('content', serialize(value))
  36. }}
  37. >
  38. <Editable />
  39. </Slate>
  40. )
  41. }

它也正常工作了!现在你保存的是纯文本。

你可以将你所喜欢的格式仿照这个策略去保存。你可以序列化为为 HTML,Markdown,甚至是根据你的实际情况定制的 JSON 格式。

🤖 请注意,虽然你可以用任何喜欢的方式去序列化值,但是他们需要被权衡。序列化过程本身是有成本的,有些格式可能比其他格式更加难以使用。通常来说,我们建议仅当在你有特殊用途的时候才编写自己的格式。另外,通常使用 Slate 默认的格式是最好的。