You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 21:29:52