I am using monaco-edtor to create a formula editor in React and Nextjs, I have an edit button to show and hide the editor, the editor only gets shown/mounted only when the user clicks the edit button.
at first, mounting the suggestion is coming as intended, but when the user hides and shows the editor same elements are repeated again as shown in the picture below is there any way to correct this
The photo of the suggestion window.
My blue print of my code is like
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}
/>
)
}
I solved the problem I added a state completionDisposable
and seated the function returned by the monaco.languages.registerCompletionItemProvider
to it and called as a clean-up function useEffect the modified code is given below
The modification is followed by the comments // Beginning of Added Segment
and // Setting the disposable object
if you understood and works for you don't forget to upvote
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}
/>
);
};