react-monaco-editor icon indicating copy to clipboard operation
react-monaco-editor copied to clipboard

Race condition: undo doesn't work correctly when interacting with handlers

Open sorawee opened this issue 6 years ago • 7 comments

Consider:

import React, {useState} from 'react';
import MonacoEditor from 'react-monaco-editor';

const Child = ({code, handleChange, i}) =>
  <>
    <div>{i + ""}</div>
    <MonacoEditor width="800" height="600" value={code} onChange={handleChange} />
  </>;

const App = () => {
  const [code, setCode] = useState('hello world');
  const [i, setI] = useState(0);
  const handleChange = (e) => {
    // variant 1
    setCode(e);
    setI(i + 1);

    // variant 2
    // setI(i + 1);
    // setCode(e);
  };
  return <Child i={i} code={code} handleChange={handleChange} />;
};

export default App;

Variant 1 works correctly. If you type text and then undo, it reverts back to the previous state correctly.

Variant 2 doesn't work correctly, even though it looks equivalent to variant 2. If you type text and then undo, it does revert back to the previous state. However, because we call setI first, there's a discrepancy of this.__current_value and this.props.value at that particular moment, causing the editor to immediately update this.__current_value with undo stops added. Consequently:

  • the cursor is reset back to the beginning
  • undo stack is totally broken. The more you undo, the more you put stuff in undo stack.

sorawee avatar May 29 '19 17:05 sorawee

In case this is useful.

undo-race-condition

sorawee avatar May 29 '19 17:05 sorawee

Can you try before and after https://github.com/react-monaco-editor/react-monaco-editor/pull/212 was merged?

domoritz avatar May 29 '19 18:05 domoritz

Before #212, we have an amalgam of two problems. The second variant makes it impossible to undo.

sorawee avatar May 29 '19 18:05 sorawee

Thanks for the issue report. Do you know this is an issue with Monaco react or just monaco itself?

domoritz avatar May 29 '19 19:05 domoritz

I believe it's an issue with react-monaco-editor. componentDidUpdate didn't consider the case where it itself is called prematurely (by React).

sorawee avatar May 29 '19 19:05 sorawee

This is still an issue even after the recent updates.

domoritz avatar Jul 20 '19 16:07 domoritz

Just a note that a possible side-step is using editor.setValue() instead of passing a value prop to <MonacoEditor>.

pastudan avatar May 09 '20 10:05 pastudan