Previous:
使用插件


保存到数据库

既然现在你已经了解了 Slate 编辑器的基本功能了,现在你关注的可能是如何存储你编辑的内容,这样就可以在返回应用的时候下载了。

在这篇教程中,我们将展示如何控制 Slate 存取编辑内容到数据库。

我们从一个基础编辑器开始:

import { Editor, State } from 'slate'

const initialState = State.fromJSON({
  document: {
    nodes: [
      {
        kind: 'block',
        type: 'paragraph',
        nodes: [
          {
            kind: 'text',
            ranges: [
              {
                text: 'A line of text in a paragraph.'
              }
            ]
          }
        ]
      }
    ]
  }
})

class App extends React.Component {

  state = {
    state: initialState
  }

  onChange = ({ state }) => {
    this.setState({ state })
  }

  render() {
    return (
      <Editor
        state={this.state.state}
        onChange={this.onChange}
      />
    )
  }

}

这会在页面上渲染出一个基础的 Slate 编辑器,在输入时内容会变动。不过如果你刷新页面,所有内容都会回退到一开始的空白状态!

我们现在需要把你的变更保存下来。在这个示例中,我们只会使用 Local Storage,不过这已经足够让你在实际实现数据库存取时有一个基础的概念了。

所以,我们需要在 onChange 回调中保存 state 状态。不过,onChange 中接受的 state 参数是一个不可变对象,我们不能够直接保存它。我们需要首先将其序列化为一个我们能够理解的格式,比如 JSON!

const initialState = State.fromJSON({
  document: {
    nodes: [
      {
        kind: 'block',
        type: 'paragraph',
        nodes: [
          {
            kind: 'text',
            ranges: [
              {
                text: 'A line of text in a paragraph.'
              }
            ]
          }
        ]
      }
    ]
  }
})

class App extends React.Component {

  state = {
    state: initialState
  }

  onChange = ({ state }) => {
    // 将 state 保存到 Local Storage。
    const content = JSON.stringify(state.toJSON())
    localStorage.setItem('content', content)

    this.setState({ state })
  }

  render() {
    return (
      <Editor
        state={this.state.state}
        onChange={this.onChange}
      />
    )
  }

}

现在不管在什么时候编辑页面,只要你查看 Local Storage,你就能看到 content 值发生改变。

不过…如果你刷新页面,一切都要从头再来了。这是因为我们需要保证初始状态从同样的 Local Storage 位置中拉取出来,像这样:

// 保证只要 Local Storage 中存在初始状态,则从中拉取之。
const existingState = JSON.parse(localStorage.getItem('content'))
const initialState = State.fromJSON(existingState || {
  document: {
    nodes: [
      {
        kind: 'block',
        type: 'paragraph',
        nodes: [
          {
            kind: 'text',
            ranges: [
              {
                text: 'A line of text in a paragraph.'
              }
            ]
          }
        ]
      }
    ]
  }
})

class App extends React.Component {

  state = {
    state: initialState
  }

  onChange = ({ state }) => {
    const content = JSON.stringify(state.toJSON())
    localStorage.setItem('content', content)

    this.setState({ state })
  }

  render() {
    return (
      <Editor
        state={this.state.state}
        onChange={this.onChange}
      />
    )
  }

}

现在你就能够在页面刷新后保存变更了!

不过,如果你检查 change 回调,会发现目前 每次 编辑器中的变更都会存储到 Local Storage 中,甚至只有选择范围变更时都会!这是因为 onChange每次 变更时都被调用了。对于 Local Storage 来说这倒没什么,不过如果你是将内容通过 HTTP 请求存储到数据库的话,这就会带来许多不必要的请求。你可以通过对比前一状态下 document 值的方式来修复这个问题。

const existingState = JSON.parse(localStorage.getItem('content'))
const initialState = State.fromJSON(existingState || {
  document: {
    nodes: [
      {
        kind: 'block',
        type: 'paragraph',
        nodes: [
          {
            kind: 'text',
            ranges: [
              {
                text: 'A line of text in a paragraph.'
              }
            ]
          }
        ]
      }
    ]
  }
})

class App extends React.Component {

  state = {
    state: initialState
  }

  onChange = ({ state }) => {
    // 保存前检查 document 是否改变。
    if (state.document != this.state.state.document) {
      const content = JSON.stringify(state.toJSON())
      localStorage.setItem('content', content)
    }

    this.setState({ state })
  }

  render() {
    return (
      <Editor
        state={this.state.state}
        onChange={this.onChange}
      />
    )
  }

}

现在你的内容就只有在变更时才会保存了!

搞定—你可以向数据库存储 JSON 了。

不过如果你需要 JSON 以外的格式呢?好吧,你需要以不同的方式序列化 state 了。比如,如果你需要以纯文本而非 JSON 的形式存储内容,你可以通过 Slate 自带的 Plain 序列化器来实现。像这样:

// 切换到 Plain 序列化器。
import { Editor, Plain } from 'slate'

const existingState = localStorage.getItem('content')
const initialState = Plain.deserialize(existingState || 'A string of plain text.')

class App extends React.Component {

  state = {
    state: initialState
  }

  onChange = ({ state }) => {
    if (state.document != this.state.state.document) {
      const content = Plain.serialize(state)
      localStorage.setItem('content', content)
    }

    this.setState({ state })
  }

  render() {
    return (
      <Editor
        state={this.state.state}
        onChange={this.onChange}
      />
    )
  }

}

可以了!现在你保存的内容就是纯文本了。

不过,有时候你可能会需要一些更加定制化的内容,并且也会更复杂…像经典的 HTML。这时候,看看下一篇教程吧…


Next:
存取 HTML 内容


results matching ""

    No results matching ""