如何在@monaco-editor/react中配置模型监听器使DiagnosticsAdapter生效?
解决方案
问题的核心是Monaco Editor实例不一致以及模型创建时机不匹配,以下是修复步骤:
1. 修改DiagnosticsAdapter,接收外部传入的Monaco实例
不再直接import monaco,而是通过构造函数注入Editor组件提供的实例,确保监听器注册到正确的实例上:
import type * as Monaco from "monaco-editor"; export class DiagnosticsAdapter { private _disposables: Monaco.IDisposable[] = []; private _listener = Object.create(null); private monaco: typeof Monaco; constructor(monaco: typeof Monaco) { this.monaco = monaco; console.log("herehere in constructor"); const onModelAdd = (model: Monaco.editor.IModel): void => { console.log("herehere onModelAdd"); let handle; const changeSubscription = model.onDidChangeContent(() => { clearTimeout(handle); handle = setTimeout(() => console.log("call validation"), 500); }); this._listener[model.uri.toString()] = { dispose() { changeSubscription.dispose(); clearTimeout(handle); } }; console.log("call validation"); }; const onModelRemoved = (model: Monaco.editor.IModel): void => { console.log("herehere onModelRemoved"); this.monaco.editor.setModelMarkers(model, "abc", []); const key = model.uri.toString(); if (this._listener[key]) { this._listener[key].dispose(); delete this._listener[key]; } }; console.log("herehere 5"); this._disposables.push(this.monaco.editor.onDidCreateModel(onModelAdd)); console.log("herehere 6"); this._disposables.push(this.monaco.editor.onWillDisposeModel(onModelRemoved)); console.log("herehere 7"); this._disposables.push( this.monaco.editor.onDidChangeModelLanguage((event) => { console.log("herehere 8"); onModelRemoved(event.model); console.log("herehere 9"); onModelAdd(event.model); }) ); console.log("herehere 10"); this._disposables.push({ dispose() { for (const model of this.monaco.editor.getModels()) { onModelRemoved(model); } } }); console.log("herehere 11"); // 手动处理已存在的模型(onMount触发时模型已创建) this.monaco.editor.getModels().forEach(onModelAdd); } public dispose(): void { this._disposables.forEach((d) => d && d.dispose()); this._disposables = []; } }
2. 在App组件中传递Monaco实例并管理适配器生命周期
将onMount回调中拿到的Monaco实例传入DiagnosticsAdapter,同时用useRef保存实例,在组件卸载时销毁以避免内存泄漏:
import React, { useRef, useEffect } from "react"; import Editor from "@monaco-editor/react"; import { DiagnosticsAdapter } from "./language-feature"; function App() { const adapterRef = useRef(null); function handleEditorDidMount(editor, monaco) { monaco.languages.register({ id: "mySpecialLanguage" }); // 将Editor提供的monaco实例传入适配器 adapterRef.current = new DiagnosticsAdapter(monaco); } // 组件卸载时销毁适配器 useEffect(() => { return () => { if (adapterRef.current) { adapterRef.current.dispose(); } }; }, []); return ( <div className="App"> <Editor height="90vh" defaultLanguage="mySpecialLanguage" defaultValue="// some comment" onMount={handleEditorDidMount} /> </div> ); } export default App;
关键原因说明
- 实例一致性:
@monaco-editor/react内部维护独立的Monaco实例,直接从monaco-editor包import的实例和组件使用的实例不共享状态,导致监听器无法捕获事件。通过构造函数注入实例解决该问题。 - 模型时机:Editor组件在
onMount回调触发前已完成模型创建,因此需要手动遍历已存在的模型并执行onModelAdd,确保已有模型被处理。
内容的提问来源于stack exchange,提问作者SoftTimur
相关产品推荐
相关产品推荐

