go to index

程序员日记20250419

read time 2 min read
react monaco 编辑器

React

MonacoEditor编辑多实例问题

在开发工具匠《代码对比》工具的时候,需要在一个页面渲染左右两个编辑器,原代码如下

plaintext
 const handleCodeChange = useCallback((newValue: string, side: 'left' | 'right') => {
      console.log(`Code change from ${side}:`, newValue);

      if (side === 'left') {
          setLeftCode(newValue || '');
      } else {
          setRightCode(newValue || '');
      }
  }, []);

<div className="flex gap-4">
    <div className="w-1/2">
        <MonacoEditor
            width="100%"
            height="400"
            language={language}
            value={leftCode}
            options={options}
            onChange={(newValue) => handleCodeChange(newValue, 'left')}
        />
    </div>
    <div className="w-1/2">
        <MonacoEditor
            width="100%"
            height="400"
            language={language}
            value={rightCode}
            options={options}  
            onChange={(newValue) => handleCodeChange(newValue, 'right')}
        />
    </div>
</div>

这个时候会出现一个现象,就是即使我们在左编辑器内输入内容,实际上回调的还是右编辑器的方法,也就是hanldCodeChange里一直打印的是right

通过尝试给编辑器加key或者ref 都没有解决,最终通过查阅,发现根本原因是因为多实例的情况下monaco实际上是复用的model,所以解决办法就是,将是将编辑器绑定到不同的model下,具体代码如下

plaintext
 const handleEditorDidMount = useCallback((editor, monaco, side) => {
    if (side === 'left') {
        leftEditorRef.current = editor;
        if (!leftModelRef.current) {
            leftModelRef.current = monaco.editor.createModel(
                leftCode,
                language,
                monaco.Uri.parse('inmemory://model/left')
            );
        }
        editor.setModel(leftModelRef.current);
        editor.onDidChangeModelContent(() => {
            setLeftCode(editor.getValue())
          })
    } else {
        rightEditorRef.current = editor;
        if (!rightModelRef.current) {
            rightModelRef.current = monaco.editor.createModel(
                rightCode,
                language,
                monaco.Uri.parse('inmemory://model/right')
            );
        }
        editor.setModel(rightModelRef.current);
        editor.onDidChangeModelContent(() => {
            setRightCode(editor.getValue())
          })
    }
}, [language, leftCode, rightCode]);

<div className="flex gap-4">
    <div className="w-1/2">
        <MonacoEditor
            width="100%"
            height="400"
            language={language}
            value={leftCode}
            options={options}
            editorDidMount={(editor, monaco) => handleEditorDidMount(editor, monaco, 'left')}
        />
    </div>
    <div className="w-1/2">
        <MonacoEditor
            width="100%"
            height="400"
            language={language}
            value={rightCode}
            options={options}
            editorDidMount={(editor, monaco) => handleEditorDidMount(editor, monaco, 'right')}
        />
    </div>
</div>