6

I'm trying to have a function run only when the contentState itself has changed, not just the editorState.

My idea right now would be to store the old contentState as a string and compare it to the new contentState as a string, but this seems awfully wasteful to be converting states to strings and comparing them. Is there a better way?

Slbox
  • 10,957
  • 15
  • 54
  • 106

3 Answers3

4

you can simply compare the value of your old state and the value of your new state you don't have to convert it to string.

EDIT: and here is a concept about react state that you don't have worry about a large state object as best practices recommend to do that way

Common misconception: state is held in a large object. It’s just object referencing a few other objects. Nothing large about it.

Md.Estiak Ahmmed
  • 1,553
  • 9
  • 14
  • Fair point, but it still seems wasteful to compare this relatively large object on every click, key press, etc. Am I overthinking this? I know one little thing like this isn't going to kill performance, but it seems very wasteful. Is this the least wasteful way? – Slbox Aug 27 '16 at 15:38
  • it's ok to compare them on such case as you mention for a `large object` when there is no easy way around to `update` them with a `new state`. – Md.Estiak Ahmmed Aug 27 '16 at 15:45
  • 2
    Note that since they are immutable objects, the comparison is quick to do. It's comparing identity, not contents. That is, `this.state.editorState.getCurrentContent() === newEditorState.getCurrentContent()` – Ishmael Smyrnow Feb 14 '17 at 16:30
  • This doesn't work if you want to exclude changes to selection state, and just want to compare content state (blocks and entities) – Dmitry Minkovsky Aug 01 '18 at 23:35
0

I have used another approach for checking whether the Editor content has changed or not.

Basically I am making use of an npm module deep-equal to compare raw contentState objects (i.e contentState converted to simple JS object using convertToRaw function). In your onChange handler, compare the old and new raw contentState objects.

Note: Comparison by deep-equal module is around 5 times faster than wrapping node's assert.deepEqual() in a try/catch.

Here is the onChange handler code:

const deepEqual = require('deep-equal');

this.onChange = (editorState) => {

    let oldContent = convertToRaw(this.state.editorState.getCurrentContent());
    let newContent = convertToRaw(editorState.getCurrentContent());

    let sameContent = deepEqual(oldContent, newContent);

    this.setState({editorState});

    if (sameContent === false)
      console.log('Content has changed.');
}
Faisal Mq
  • 5,036
  • 4
  • 35
  • 39
0

This isn't so different from Faisal Mushtaq's answer, but includes a few improvements. In your component's constructor:

// keep track of the last state
let lastContentState = this.state.editorState.getCurrentContent()

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

  // push your handling code onto the call stack with a setTimeout
  // so that it doesn't block handling new inputs to the editor
  setTimeout(() => {

    // first-time focus or blur, no change to content
    if (!editorState.getLastChangeType()) return

    const currentContentState = editorState.getCurrentContent()

    // ES6 to compare, could use Immutable.is() instead
    const toHandle = !Object.is(lastContentState, currentContentState)

    if (toHandle) {
      // your handler function, eg passed in as a prop
      this.props.handleChange(currentContent)

      // current content becomes last content
      lastContentState = currentContentState
    }

  }, 0)
}
pfkurtz
  • 494
  • 3
  • 7