我正在使用 monaco-edtor 在 React 和 Nextjs 中创建公式编辑器,我有一个编辑按钮来显示和隐藏编辑器,只有当用户单击编辑按钮时编辑器才会显示/安装。
首先,安装建议是按预期进行的,但是当用户隐藏并显示编辑器时,相同的元素再次重复,如下图所示,有什么方法可以纠正这个问题
建议窗口的照片。
我的代码蓝图就像
export const MonacoEditor = () => {
const editorRef = useRef<monacoEditor.editor.IStandaloneCodeEditor | null>(
null,
);
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();
}
});
// Define your custom language
monaco.languages.register({
id: "custom-language",
});
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",
});
monaco.languages.registerCompletionItemProvider("custom-language", {
provideCompletionItems: async (_model, position) => {
const currentWord = getCurrentWord(editorRef.current, position);
// Make a request to your backend API to fetch suggestions based on the user's input
const response = await fetch("http://localhost:8000/fewLabels", {
method: "GET",
});
const suggestions: Suggestion = await response.json();
console.log("suggestions ", suggestions);
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,
),
}));
console.log("completionItems ", completionItems);
return {
suggestions: completionItems,
};
},
});
}
return(
<Editor
height="70px"
width={"800px"}
defaultLanguage="custom-language"
onMount={HandleEditorDidMount}
/>
)
}
我解决了这个问题,我添加了一个状态
completionDisposable
,并将monaco.languages.registerCompletionItemProvider
返回的函数设置为它,并作为清理函数调用useEffect,修改后的代码如下
修改后面有评论
// Beginning of Added Segment
和
// Setting the disposable object
如果您理解并为您工作,请不要忘记点赞
export const MonacoEditor = () => {
const editorRef = useRef<monacoEditor.editor.IStandaloneCodeEditor | null>(
null,
);
// Beginning of Added Segment
const [completionDisposable, setCompletionDisposable] = useState<monacoEditor.IDisposable>();
useEffect(() => {
return () => {
if (
completionDisposable?.dispose &&
typeof completionDisposable.dispose === "function"
) {
completionDisposable.dispose();
}
};
}, [completionDisposable]);
// End of added segment
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();
}
});
// Define your custom language
monaco.languages.register({
id: "custom-language",
});
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",
});
// Setting the disposable object
setCompletionDisposable(
monaco.languages.registerCompletionItemProvider("custom-language", {
provideCompletionItems: async (_model, position) => {
const currentWord = getCurrentWord(editorRef.current, position);
// Make a request to your backend API to fetch suggestions based on the user's input
const response = await fetch("http://localhost:8000/fewLabels", {
method: "GET",
});
const suggestions: Suggestion = await response.json();
console.log("suggestions ", suggestions);
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,
),
}));
console.log("completionItems ", completionItems);
return {
suggestions: completionItems,
};
},
}),
);
}
return (
<Editor
height="70px"
width={"800px"}
defaultLanguage="custom-language"
onMount={HandleEditorDidMount}
/>
);
};
我刚刚稍微更改了@SREERAG R NANDAN 的答案以满足我的需求,如下所示:
const [completionDisposable, setCompletionDisposable] = useState(null)
useEffect(() => {
return () => {
if (
completionDisposable &&
typeof completionDisposable.dispose === 'function'
) {
completionDisposable.dispose()
}
}
}, [completionDisposable])
const handleOnMount = (editor, monaco) => {
setCompletionDisposable(
monaco.languages.registerCompletionItemProvider('json', {
provideCompletionItems: function (model, position) {
const suggestions = []
quickSuggestions.map((word) => {
suggestions.push({
label: word,
kind: monaco.languages.CompletionItemKind.Text,
insertText: word,
})
})
return {
suggestions: suggestions,
}
},
})
)
}
return ( <Editor
ref={editorRef}
height="90vh"
width="800px"
language="json"
theme="solarized-light"
value={updatedJson}
options={options}
onChange={handleEditorChange}
onMount={handleOnMount}
/>)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
对我来说效果很好