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
相关产品推荐
相关产品推荐

