Monaco Editor切换全屏/窗口缩放时出现ResizeObserver循环错误
React集成Monaco Editor时的ResizeObserver循环错误问题
问题现象
在React组件中使用Monaco Editor时,切换全屏模式或调整浏览器窗口大小会持续触发以下错误:
ResizeObserver loop completed with undelivered notifications. at handleError (http://localhost:3000/static/js/bundle.js:XXXXX:XX) at http://localhost:3000/static/js/bundle.js:XXXXX:XX
相关组件代码
import { useRef } from "react"; import { Editor } from "@monaco-editor/react"; import { useData } from "../../context/DataContext"; const CodeEditor = ({ language, editorContent, handleChange, theme }) => { const debounceTimeout = useRef(null); const editorRef = useRef(null); const latestContent = useRef(editorContent); const { isGenerating, handleEditorValidation, isFullScreen } = useData(); const handleEditorChange = (value) => { latestContent.current = value; clearTimeout(debounceTimeout.current); debounceTimeout.current = setTimeout(() => { handleChange(latestContent.current); }, 3000); }; return ( <div className={`${isFullScreen ? 'h-[60vh] pt-1' : 'h-[55vh]'} w-full rounded-lg`}> <Editor onValidate={handleEditorValidation} language={language} value={editorContent} theme={theme} onMount={(editor) => (editorRef.current = editor)} onChange={handleEditorChange} options={{ automaticLayout: true, fontSize: 18, fontFamily: "cursive", fontLigatures: true, lineNumbers: "on", minimap: { enabled: true }, scrollbar: { verticalScrollbarSize: 20, horizontalScrollbarSize: 10, }, tabSize: 8, insertSpaces: true, formatOnType: true, formatOnPaste: true, wordWrap: "off", scrollBeyondLastLine: false, renderLineHighlight: "all", readOnly: isGenerating, cursorBlinking: "smooth", suggestOnTriggerCharacters: true, quickSuggestions: true, parameterHints: { enabled: true }, folding: true, occurrencesHighlight: true, autoClosingBrackets: "always", autoClosingQuotes: "always", guides: { indentation: true, highlightActiveBracketPair: true, }, bracketPairColorization: { enabled: true }, }} /> </div> ); }; export default CodeEditor;
根因分析
- Monaco Editor的automaticLayout机制:开启
automaticLayout: true后,Monaco依赖ResizeObserver监听容器尺寸变化,若容器尺寸短时间内频繁变动(比如全屏切换、窗口快速缩放),会触发ResizeObserver的循环通知未交付错误。 - 父容器尺寸突变:全屏切换时父容器高度从55vh变为60vh,窗口调整时容器宽高也会持续变化,导致Monaco频繁触发布局重计算。
- 潜在的回流循环:若Editor或其容器在ResizeObserver回调中修改DOM属性,会形成布局修改-监听触发-再修改的反馈循环,加剧错误出现的概率。
解决方案
方案1:禁用automaticLayout,手动控制布局更新
关闭自动布局,通过监听尺寸变化手动调用Monaco的布局方法,结合防抖减少频繁触发:
import { useRef, useEffect } from "react"; // ... 其他导入不变 const CodeEditor = ({ language, editorContent, handleChange, theme }) => { // ... 现有ref和函数不变 useEffect(() => { const handleResize = () => { if (editorRef.current) { clearTimeout(debounceTimeout.current); debounceTimeout.current = setTimeout(() => { editorRef.current.layout(); }, 200); } }; window.addEventListener('resize', handleResize); document.addEventListener('fullscreenchange', handleResize); return () => { window.removeEventListener('resize', handleResize); document.removeEventListener('fullscreenchange', handleResize); clearTimeout(debounceTimeout.current); }; }, []); return ( <div className={`${isFullScreen ? 'h-[60vh] pt-1' : 'h-[55vh]'} w-full rounded-lg`}> <Editor // ... 其他属性不变 options={{ automaticLayout: false, // ... 其他配置不变 }} /> </div> ); };
方案2:全局捕获错误,隐藏控制台报错
如果不想修改布局逻辑,可以全局拦截该特定错误,避免其在控制台显示(仅隐藏错误,未解决根源):
// 在项目入口文件(如index.js)添加 const originalError = console.error; console.error = (...args) => { if (args[0]?.includes('ResizeObserver loop completed with undelivered notifications')) { return; } originalError.apply(console, args); };
方案3:优化父容器尺寸变化
给父容器添加过渡动画,让尺寸变化更平缓,降低ResizeObserver的触发频率:
/* 全局样式或组件内样式 */ .code-editor-container { transition: height 0.3s ease; }
修改组件中的容器className:
<div className={`code-editor-container ${isFullScreen ? 'h-[60vh] pt-1' : 'h-[55vh]'} w-full rounded-lg`}>
内容的提问来源于stack exchange,提问作者Santhosh Shanmugam
相关产品推荐
相关产品推荐

