Best performance method to check if contentState changed in DraftJS, or just editorState
Asked Answered
L

3

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?

Limelight answered 27/8, 2016 at 15:16 Comment(1)
if you share the comparing code we can help in more details if my answer doesn't help you muchCaterina
C
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.

Caterina answered 27/8, 2016 at 15:36 Comment(4)
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?Limelight
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.Caterina
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()Hames
This doesn't work if you want to exclude changes to selection state, and just want to compare content state (blocks and entities)Disinclination
M
1

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)
}
Monoculture answered 10/12, 2016 at 2:9 Comment(0)
W
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.');
}
Wherewith answered 25/10, 2016 at 14:23 Comment(2)
It's a lot more expensive than just checking a reference equality as suggested by the most upvoted answer.Sounding
This is the only way if you only want to take content (blocks/entities) into account.Disinclination

© 2022 - 2024 — McMap. All rights reserved.