使用 react-monaco-editor 正确地消除调用 onChange 以更新

correctly debouncing a call onChange to update using react-monaco-editor

编辑:

很好地总结了我的问题:monaco 编辑器从状态中获取当前值,而 debounce 阻止状态触发。我怎样才能让用户继续不间断地输入而不进行不必要的调用来更新代码。

-----结束编辑-----

好的,所以我有一个使用 react-monaco-editor 作为代码编辑器面板的 React 应用程序(无 CRA)。当用户键入 onChange 事件时,我想调用去抖更新操作,但这现在不起作用。

设置不是很简单,但我有一个父组件 CodeEditorPanel,它有一个子组件 monacoEditor。我已经删除了尽可能多的与问题没有直接关系的代码,但如果需要可以添加更多详细信息。

在自动模式 (UPDATE_METHODS.AUTOMATIC.value) 中使用 updateCode 工作得很好,但计算量很大,但是当我使用去抖动模式 (UPDATE_METHODS.DEBOUNCE.value) 时,更改变得混乱,看起来它们使用的是旧的值(这听起来像是如果我不使用 useRef 但我使用了会发生什么。)。无论如何,有些事情(不是这样)显然是不对的,如果能帮助我发现我的(希望是小的)错误,我将不胜感激。

// CodeEditorPanel.js
import React, { useRef } from 'react';

const CodeEditorPanel = ({
  updateMethod, // editor setting, user can choose: automatic, manual, throttled, debounced
  updateCode, // the update action I want to debounce
}) => {

  const debouncedUpdate = useRef(debounce(updateCode, debounceInterval)).current;

  const getUpdateMethod = () => {
    switch (updateMethod) {
      case UPDATE_METHODS.DEBOUNCE.value:
        return debouncedUpdate;
      case UPDATE_METHODS.THROTTLE.value:
        return throttledUpdate;
      case UPDATE_METHODS.MANUAL.value:
        return ({ code, selectedFile }) => updateCode({ code, selectedFile, buffer: true });
      case UPDATE_METHODS.AUTOMATIC.value:
      default:
        return updateCode;
    }
  };

  // in reality there is a function call before update getUpdateMethod but I'm trying to simplify
  return <MonacoEditor updateCode={getUpdateMethod()} />;

};

// 
class monacoEditor extends Component {

  onChange(newValue, e) {
    const { selectedFile, updateCode } = this.props;

    // want to debounce this bad boy right here
    updateCode({ code: newValue, selectedFile });
  }

  render() {
    <MonacoEditor
      ref="monaco"
      language={language}
      theme="vs-dark"
      defaultValue=""
      value={selectedFile.content}
      options={MONACO_DEFAULT_OPTIONS}
      onChange={this.onChange}
      editorWillMount={this.editorWillMount}
      editorDidMount={this.editorDidMount}
    />
  }

}

我想出了一个适合我的解决方案,但如果其他人有想法,我仍然很感兴趣。

所以我所做的是:

  1. 在我的组件中创建一个局部状态变量并初始化为代码属性。
  2. 在 onChange 方法中,我没有调用动作创建者,而是更新了本地状态。
  3. 我在设置为一秒的组件中添加了一个空闲计时器。所以如果用户停止输入一秒钟,它会调用动作创建器来更新 redux。

我的做法是two-fold:

  1. 如果需要立即采取行动(例如代码完成),那么我会在每次更改时执行任务。

  2. 如果可以延迟操作(例如错误检查),那么实际更改并不重要。在那种情况下,我会启动一个计时器(每次更改时都会重置)并且 运行 触发所需的操作。在这种情况下不需要保持状态,因为没有必要。

当然,如果实际更改仍然很重要(例如,将操作限制在自上次 运行 以来修改的某个范围内),那么您当然需要存储它(或派生的值,如范围)。

React MonacoEditor

我还有一个想法,即在不调用 onChange 事件的情况下获取 React monacoeditor 值。 创建 MonacoEditor 的引用。

this.editorRef = React.createRef();

之后添加对 MonacoEditor 标签的引用。

<MonacoEditor
   ref={this.editorRef}
   height="500px"
   language="json"
   // editorDidMount={this.editorDidMount.bind(this)}
   // onChange={this.onChange.bind(this)}
   value={this.state.code}
   options={options}
 />

然后添加按钮并为 onClick 事件创建函数,如下代码

 async saveData(){
    const currentCode = this.editorRef.current.editor.getModel().getValue();
    this.setState({code:currentCode});
    this.editorRef.current.editor?.focus();

  }

您将通过单击保存按钮获得编辑器的更新值。