monaco-react: ControlledEditor doesn't fire onChange upon Undo/Redo
Undo and redo typically change the contents of a ControlledEditor but onChange doesn’t fire. I see the code has an explicit check that prevents this which was added in 2.3.0, but it’s not clear why. Undo and redo can change the content of the editor just like any other operation, so onChange should fire.
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Comments: 21 (7 by maintainers)
Awesome 🎉 🎉 happy to help 😃
@patrickshipe @seraph0x @RickeyWard @SivaKranthiKumar @jdroigk @jpeterson @travisdahl @rosslovas hello everyone 🙂
The problem is solved. A check has been missed during rewriting. Let’s thank @patrickshipe for a great catch.
The new version (v3.4.2) has already published 🎉 If it’s possible, please check it.
Thank you all for your support!
Hello @rosslovas, @travisdahl. Sorry for the late answer guys.
I can approve - there is such kind of problem. We have faced it a couple of months ago. The explicit check you have already noticed is added intentionally. I’ll work on it, and keep you up to date here.
Thank you for your support!
Maybe I am missing something @suren-atoyan, but it seems that part of the issue is that the controlled editor will always run the
executeEditswhenvalueprop changes, even ifvalue === editorRef.current.getModel().getValue(), which quickly clutters the undo stack. If thevalueprop changes but it strictly equals the model’s current value, why do we make the update?Hello @patrickshipe. You are right. There is no need, moreover, it will “spoil” the undo stack. I think the problem is that when I was rewriting it from a class component into a function component with hooks (a while ago), and converting big
componentDidMountinto smalluseUpdates, I missed that check and got an illusion of necessity ofexecuteEditsas there was a dependency array withvalue(something like thisuseUpdate(...., [value])). Long story short, that’s a great catch, thank you, I am sure it will solve the problem with undo/redo. Let me check it today. And if everything is okay, I’ll publish a new version.@RickeyWard Thanks for sharing your implementation! This worked great for me to fix this bug.
I noticed another bug whereby holding backspace would skip some characters. (Basically, two onChange events would go up the React component chain before the first one’s new value came back down the chain. I’m using Redux, so this might be related to a delay in Redux.)
I solved it by treating <Editor> as a true uncontrolled component (value prop is constant and all value updates happen imperatively) and debouncing the onChange handler which also drastically improved performance for the controlled editor. If anyone is interested, I’ll include my modifications to @RickeyWard’s code below.
ControlledEditor.jsx
I noticed that the
_isControlledEditorprop can be removed with no apparent ill effects. All it seems to do is force tokenization on every update - why do you need that?Hello @jpeterson, if you want to solve the problem in your particular case, I can suggest you use a custom controlled component made by you. I mean, the
Controlled Editorcomponent we have now is just a small wrapper around the mainEditor component. So, you can easily implement it, for a hint you can examine this file. Until we will find a universal solution to solve problems of all.