You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多Monaco Editor实例下Hover Provider的正确配置方案咨询

Monaco Editor多实例场景下语言、编辑器、模型与Hover Provider的正确组织方式

核心问题根源

你遇到的重复SOURCE提示,是因为每个组件实例都调用了全局的monaco.languages.registerHoverProvider,导致同一语言被注册了多个相同的Hover Provider,所有实例都会触发所有Provider的逻辑。

正确组织方式

1. 语言与通用Provider全局唯一注册

Monaco Editor的语言和全局Provider是全局作用域的,不需要在每个组件实例中重复注册:

  • 把语言注册(monaco.languages.register)和通用Hover Provider(不依赖组件实例状态的逻辑)放在应用初始化阶段执行,比如入口文件、单独的Monaco配置模块里,只执行一次。
  • 这样所有使用该语言的编辑器实例都会共享同一个Provider,不会出现重复触发的问题。

示例代码(全局配置):

// monaco-config.ts
import * as monaco from 'monaco-editor';

// 全局注册一次自定义语言
monaco.languages.register({ id: 'mySpecialLanguage' });

// 全局注册通用Hover Provider
monaco.languages.registerHoverProvider('mySpecialLanguage', {
  provideHover(model, position) {
    // 通用提示逻辑,比如基于语法解析返回内容
    return {
      contents: [{ value: '**SOURCE** 通用提示内容' }]
    };
  }
});

2. 组件实例仅负责编辑器与模型的创建

在ResizableMonacoEditor组件中,只需要完成编辑器实例的创建、模型关联,不需要再处理语言或通用Provider的注册:

  • 创建编辑器时指定已注册的语言mySpecialLanguage即可自动关联全局的Hover Provider。
  • 如果需要实例专属的Hover逻辑(比如依赖组件自身的状态、props),不要用全局注册方法,而是调用编辑器实例的registerHoverProvider方法,该方法注册的Provider仅对当前编辑器实例生效。

示例代码(组件内部):

// ResizableMonacoEditor.tsx
import * as monaco from 'monaco-editor';
import { useEffect, useRef } from 'react';

const ResizableMonacoEditor = ({ value, customHint }) => {
  const editorRef = useRef(null);
  const containerRef = useRef(null);

  useEffect(() => {
    if (!containerRef.current) return;

    // 创建编辑器实例,关联已注册的语言
    const editor = monaco.editor.create(containerRef.current, {
      value,
      language: 'mySpecialLanguage',
      // 其他编辑器配置
    });
    editorRef.current = editor;

    // 注册实例专属的Hover Provider(仅当前编辑器生效)
    const providerDisposable = editor.registerHoverProvider('mySpecialLanguage', {
      provideHover(model, position) {
        // 基于组件自身的props/状态返回提示
        return {
          contents: [{ value: `**SOURCE** 实例专属提示: ${customHint}` }]
        };
      }
    });

    // 组件卸载时清理资源
    return () => {
      providerDisposable?.dispose();
      editor.dispose();
    };
  }, [value, customHint]);

  return <div ref={containerRef} style={{ width: '100%', height: '400px' }} />;
};

export default ResizableMonacoEditor;

3. 务必清理资源避免泄漏

组件卸载时,需要调用:

  • 编辑器实例的dispose()方法,销毁编辑器。
  • 实例专属Provider返回的Disposable对象的dispose()方法,清理该Provider。

这样可以防止残留的Provider影响其他编辑器实例,同时避免内存泄漏。

内容的提问来源于stack exchange,提问作者SoftTimur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 06:20:47