monaco-react
monaco-react copied to clipboard
Make the onMount function can have a destroy function
currently if we want to initialize some provider, because the provider return a dispose object, when the editor component destroy, we can't add a destroy function to do that just like this:
const editorDidMount: OnMount = (editor, monaco) => {
editorRef.current = editor;
monaco.languages.register({ id: 'betalpha' });
const tokenProvider = monaco.languages.setTokensProvider(
'betalpha',
new TokensProviders(),
);
const suggestions = transSug(['代码提示']);
if(suggestions.length){
const completionItemProvider = monaco.languages.registerCompletionItemProvider(
'betalpha',
{
provideCompletionItems(model, position) {
position.clone();
const word = model.getWordAtPosition(position);
const defaultReplaceRange = word ? new monaco.Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn) : monaco.Range.fromPositions(position)
const defaultRange = { replace: defaultReplaceRange, insert: defaultReplaceRange.setEndPosition(position.lineNumber, position.column) }
return {
suggestions: suggestions.map((item) => ({
range: defaultRange,
...item,
kind: item.icon
? monaco.languages.CompletionItemKind.Variable // 图标
: monaco.languages.CompletionItemKind.File,
})),
};
},
},
);
}
};
we can't destory completionItemProvider and tokenProvider
so if we can have a destroy function that we can write it like this
const editorDidMount: OnMount = (editor, monaco) => {
editorRef.current = editor;
monaco.languages.register({ id: 'betalpha' });
const tokenProvider = monaco.languages.setTokensProvider(
'betalpha',
new TokensProviders(),
);
const suggestions = transSug(['代码提示']);
let completionItemProvider;
if(suggestions.length){
completionItemProvider = monaco.languages.registerCompletionItemProvider(
'betalpha',
{
provideCompletionItems(model, position) {
position.clone();
const word = model.getWordAtPosition(position);
const defaultReplaceRange = word ? new monaco.Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn) : monaco.Range.fromPositions(position)
const defaultRange = { replace: defaultReplaceRange, insert: defaultReplaceRange.setEndPosition(position.lineNumber, position.column) }
return {
suggestions: suggestions.map((item) => ({
range: defaultRange,
...item,
kind: item.icon
? monaco.languages.CompletionItemKind.Variable // 图标
: monaco.languages.CompletionItemKind.File,
})),
};
},
},
);
}
return () => {
tokenProvider.dispose();
if (completionItemProvider) {
completionItemProvider.dispose()
}
}
};
@dingchaoyan1983 I am not sure if your suggested pattern is suitable for this particular case, especially if your issue has multiple options to be solved:
option 1) use useEffect to handle side effects
function YourCoolComponent() {
const monacoRef = useRef(null);
const [isReady, setIsReady] = useState(false);
useEffect(() => {
let tokenProvider;
let completionItemProvider;
if (isReady) {
tokenProvider = monaco.languages.setTokensProvider(...);
completionItemProvider = monaco.languages.registerCompletionItemProvider(...);
}
return () => {
tokenProvider?. dispose();
completionItemProvider?.dispose();
};
}, [isReady]);
function handleEditorDidMount(editor, monaco) {
monaco.current = monaco;
setIsReady(true);
}
return <Editor onMount={handleEditorDidMount} ... />;
}
option 2) use useMonaco to get monaco instance
import { useMonaco } from '@monaco-editor/react';
...
function YourCoolComponent() {
const monaco = useMonaco();
useEffect(() => {
let tokenProvider;
let completionItemProvider;
if (monaco) {
tokenProvider = monaco.languages.setTokensProvider(...);
completionItemProvider = monaco.languages.registerCompletionItemProvider(...);
}
return () => {
tokenProvider?. dispose();
completionItemProvider?.dispose();
};
}, [monaco]);
return <Editor ... />;
}
option 3) use useRef to store tokenProvider and completionItemProvider
function YourCoolComponent() {
const tokenProviderRef = useRef(null);
const completionItemProviderRef = useRef(null);
useEffect(() => {
return () => {
tokenProviderRef.current?. dispose();
completionItemProviderRef.current.?.dispose();
};
}, []);
function handleEditorDidMount(editor, monaco) {
tokenProviderRef.current = monaco.languages.setTokensProvider(...);
completionItemProviderRef.current = monaco.languages.registerCompletionItemProvider(...);
}
return <Editor onMount={handleEditorDidMount} ... />;
}
@suren-atoyan yeah, your suggestion is very good, they can resolve my problem also, but it is not intuitive, for options 1, I SHOULD to know the ready variable is indicate that the editor is mounted, so I NEED to know more details for this component, for option 2, does the monaco editor is mounted when monaco variable is ready?, for option 3, I should keep the references
That is all, for the component lifecycle, we just have onMount lifecycle, but we don't expose a lifecycle just like unMount, we should expose this lifecycle to developers, that they can do some cleanup work and they can also do not use this lifecycle just don't return a cleanup function
just like this code in react code
useEffect(() => {
// run effect
return () => {
//dispose the effect
}
});
I close this due to inactivity. Feel free to re-open it.