1

I've got a conditional that displays an editor while a certain prop remains true. The thing is, the data with which that editor is rendered with should change every time I select another object with which to populate that editor.

However, because the prop responsible for the conditional rendering doesn't change, even though the data with which the editor is rendered does, it refuses to re-render on state change.

I'm not particularly good at React, so, hopefully someone can explain how I can get around this little hiccup.

Conditional render

{this.state.showEditor ? (<BlockEditor routine={this.state.editorObject} />) : null}

Method that is being called.

handleShowEditor = routine => {
    this.setState({ showEditor: true });
    this.setState({ editorObject: routine });
  };

The editor component

export default class BlockEditor extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      routine: this.props.routine
    };
  }

render() {
    return (
      <div>
        <Editor
          autofocus
          holderId="editorjs-container"
          onChange={data => this.handleSave(data)}
          customTools={{}}
          onReady={() => console.log("Start!")}
          data={this.props.routine.description}
          instanceRef={instance => (this.editorInstance = instance)}
        />
      </div>
    );
  }
}
gloomyfit
  • 475
  • 1
  • 5
  • 13

3 Answers3

0

Is there a reason for setting state separately? Why not

handleShowEditor = routine => {
    this.setState({ 
        showEditor: true,
        editorObject: routine
    });
};

Keep in mind that setState is asynchronous and your implementation could lead to such weird behaviour.

zhuber
  • 5,364
  • 3
  • 30
  • 63
  • There's no reason (I'm just terrible at React), I've already made this adjustment, thanks. It does however not solve the issue, since showEditor remains true, it doesn't cause the editor to re-render using the new editorObject even though the editorObject has changed. – gloomyfit Sep 23 '19 at 07:40
  • Change in BlockEditor props should cause re-render, are you sure you have completely different routine after making change? Can you maybe show BlockEditor component code? – zhuber Sep 23 '19 at 07:45
  • Yes, I'm certain, because I tried console.log(this.state.editorObject) inside that method, and it logs, the previous state (not sure why, but it gets updated), because if I click the button to call the method again, it logs the new object. – gloomyfit Sep 23 '19 at 07:52
  • if I have this.setState({showEditor: !this.state.showEditor}), then it also works properly (since it first changes it to false, then if I click the method again, it changes it to true, this leads it to re-render, but this is not a solution, since it's awkward where I now have to click the same button to first hide the editor, before it is shown again with the new editorObject). – gloomyfit Sep 23 '19 at 07:53
  • @gloomyfit Please see this https://stackblitz.com/edit/react-ts-emtryu?file=index.tsx – zhuber Sep 23 '19 at 08:05
  • I checked out your stackblitz, and you're right, that's exactly how I've got it setup, but for some reason, it doesn't behave the same. I don't know why mine doesn't work. – gloomyfit Sep 23 '19 at 08:26
0

If you are still looking for an answer i have faced the same problem working with the same [Editor.JS][1] :).

This worked for me with functional component:

// on change fires when component re-intialize
      onChange={async (e) => {
        const newData = await e.saver.save();
    
          setEditorData((prevData) => {
             console.log(prevData.blocks);
             console.log(newData.blocks);
    
              if (
                JSON.stringify(prevData.blocks) === JSON.stringify(newData.blocks)
               ) {
                  console.log("no data changed");
                  return prevData;
              } else {
                console.log("data changed");
                return newData;
              }
           });
         }}
         // setting true to re-render when currentPage data change
         enableReInitialize={true}

Here we are just checking if data changes assign it to editorData component state and perform re-render else assign prevData as it is which will not cause re-render.

Hope it helps.

Edit:

  • i am comparing editor data blocks change which is array.
  • of course you need to perform comparison of blocks more deeply than what i am doing, you can use lodash for example. [1]: https://github.com/editor-js/awesome-editorjs
Safwat Fathi
  • 758
  • 9
  • 16
-1

As setState is asynchronous you can make another call in its callback.

Try like this

handleShowEditor = routine => {
this.setState({ 
    showEditor: true
}, () =>{
     this.setState({
       editorObject: routine
     )}
});
};
thug_
  • 893
  • 2
  • 11
  • 31