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

React+Next.js中Monaco Editor提示项重复问题求助

解决Monaco Editor重复提示项问题

问题根源在于每次组件挂载时,你都重复执行了自定义语言注册和补全提供者注册操作。Monaco Editor的语言与补全提供者是全局注册的,不会随组件卸载自动清理,多次挂载后会存在多个相同的补全提供者,最终导致提示项重复出现。

修复方案

通过标记变量记录是否已完成全局注册,确保语言和补全提供者只被注册一次,而非每次组件挂载都重复注册。

修改后的代码示例

import { useRef } from 'react';
import Editor from '@monaco-editor/react';

export const MonacoEditor = () => {
    const editorRef = useRef<monacoEditor.editor.IStandaloneCodeEditor | null>(null);
    // 组件内标记:记录是否已注册过语言和补全提供者
    const isRegisteredRef = useRef(false);
    
    function HandleEditorDidMount(
        editor: monacoEditor.editor.IStandaloneCodeEditor,
        monaco: typeof monacoEditor,
    ) {
        editorRef.current = editor;

        editorRef.current.onKeyDown((event: monacoEditor.IKeyboardEvent) => {
            if (event.keyCode === monaco.KeyCode.Enter) {
                event.preventDefault();
            }
        });

        // 仅首次挂载时执行全局注册操作
        if (!isRegisteredRef.current) {
            // 注册自定义语言
            monaco.languages.register({
                id: "custom-language",
            });

            // 注册补全提供者
            monaco.languages.registerCompletionItemProvider("custom-language", {
                provideCompletionItems: async (_model, position) => {
                    const currentWord = getCurrentWord(editorRef.current, position);

                    const response = await fetch("http://localhost:8000/fewLabels", {
                        method: "GET",
                    });

                    const suggestions: Suggestion = await response.json();
                    const completionItems = Object.keys(suggestions)
                        .filter((keyword) =>
                            keyword.toLowerCase().startsWith(currentWord.toLowerCase()),
                        )
                        .map((keyword) => ({
                            label: keyword,
                            id: keyword,
                            kind: monaco.languages.CompletionItemKind.Keyword,
                            insertText: keyword,
                            range: new monaco.Range(
                                position.lineNumber,
                                position.column - currentWord.length,
                                position.lineNumber,
                                position.column,
                            ),
                        }));

                    return {
                        suggestions: completionItems,
                    };
                },
            });

            isRegisteredRef.current = true;
        }

        // 编辑器实例配置可每次挂载更新,不影响全局状态
        editorRef.current.updateOptions({
            lineNumbers: "off",
            lineDecorationsWidth: 1,
            tabCompletion: "off",
            selectionHighlight: false,
            renderLineHighlight: "none",
            minimap: {
                enabled: false,
            },
            overviewRulerLanes: 0,
            scrollbar: {
                horizontal: "hidden",
                handleMouseWheel: true,
            },
            wordWrapColumn: -1,
            wordWrap: "on",
        });
    }

    return(
        <Editor
            height="70px"
            width={"800px"}
            defaultLanguage="custom-language"
            onMount={HandleEditorDidMount}
        />
    )
}

关键说明

  • 使用组件内部的useRef标记注册状态,避免全局变量污染,同时确保注册逻辑仅执行一次。
  • 语言注册和补全提供者属于全局配置,不需要随组件重复挂载执行;而编辑器实例的updateOptions是针对当前实例的设置,可保留每次挂载时执行。

内容的提问来源于stack exchange,提问作者SREERAG R NANDAN

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 06:02:06