Skip to content

ResizeObserverループエラー修正

問題の本質

ResizeObserver loop completed with undelivered notificationsエラーは、要素のリサイズを監視するResizeObserver APIが、ブラウザの描画サイクル内でレイアウト変更が連鎖的に発生し、通知を正常に配信できなかった場合に発生します。Reactアプリケーションでのモーダル操作後や特定のUIコンポーネント使用時に頻発します。

エラーの発生原因

主な根本原因は以下のいずれかです:

  1. ブラウザ拡張機能の干渉(LastPass、LanguageToolなど)
  2. コンポーネントの動的サイズ変更ループ(無限リサイズサイクル)
  3. 特定UIライブラリのバグや設定不備(Material UI, Ant Designなど)
  4. 複数のリサイズイベントの競合

以下に実証済みの解決策をカテゴリ別に紹介します。


解決策1: ブラウザ拡張機能を無効化

最初に確認すべき対策

多くのケース(特にreact-routerv6移行後)で、パスワードマネージャーや文法チェッカー拡張機能がトリガーになります。最も効果的な初期対策です。

  1. LastPass、LanguageToolなどの拡張機能を一時無効化
  2. エラーが消えるか確認
  3. 特定の拡張機能を特定できたら、サイトで除外設定を追加
js
// 緊急避難的な対策(本番環境では非推奨)
window.alert = function (message) {
  const ignoredKeywords = ["resizeobserver", "lastpass"];
  const lowerMessage = message.toLowerCase();
  
  if (ignoredKeywords.some(keyword => lowerMessage.includes(keyword))) {
    return; // 拡張機能関連エラーを非表示
  }
  
  // 通常のアラート処理
  console.error(message);
};

解決策2: UIコンポーネントの設定調整

Material UIのTextField対応

multilinefullWidth使用時の修正例:

js
<TextField
  multiline
  fullWidth // 問題が発生する場合はコメントアウト
  label="説明"
  sx={{
    "& textarea": {
      minHeight: "100px" // 高さを固定してリサイズループ防止
    },
    width: "99%" // fullWidth使用時は99%に変更
  }}
/>

Ant DesignのTableコンポーネント

scrollプロパティが原因の場合:

js
<Table
  // scroll={{ x: "max-content" }} // エラー発生時は削除
  dataSource={data}
  columns={columns}
/>

解決策3: ResizeObserverの実装改善

リクエストアニメーションフレーム利用

レンダリングタイミングを最適化:

js
const observer = new ResizeObserver(entries => {
  // ブラウザの描画サイクルに合わせて実行
  window.requestAnimationFrame(() => {
    if (!entries || entries.length === 0) return;
    
    // リサイズ処理実装例
    const { width, height } = entries[0].contentRect;
    console.log(`新しいサイズ: ${width}x${height}`);
  });
});

デバウンス機能の実装

複数のリサイズイベントをまとめる:

js
import { debounce } from 'lodash';

const DEBOUNCE_TIME = 100; // 100ms

const handleResize = debounce(entries => {
  entries.forEach(entry => {
    // サイズ変更処理
  });
}, DEBOUNCE_TIME);

const observer = new ResizeObserver(handleResize);

解決策4: 開発環境限定の対策

本番環境では表示されない

このエラーは開発ビルド時のみ表示される場合が多く、本番パフォーマンスには影響しません。開発中のコンソール警告が気になる場合のみ対策が必要です。

webpack開発サーバーの設定変更

webpack.config.jsでエラーハンドリングを調整:

js
module.exports = {
  devServer: {
    client: {
      overlay: {
        runtimeErrors: (error) => {
          // このエラーのみコンソールに転送
          if (error.message.includes('ResizeObserver')) {
            console.error('ResizeObserverエラー:', error);
            return false; // オーバーレイ非表示
          }
          return true; // その他エラーは表示
        },
      },
    },
  },
};

最小幅の指定

CSSで要素サイズを安定化:

css
body, .resize-target {
  min-width: 400px; /* 予期しない縮小を防止 */
}

根本原因と予防策

ResizeObserverの動作原理上、以下の条件でエラーが発生します:

  1. 要素Aのリサイズ → 要素Bのレイアウト変更
  2. 要素Bの変更 → 要素Aの再リサイズ
  3. このループがブラウザの制限値(通常5ループ)を超える

予防的対策例:

  • min-height/min-widthで要素サイズの下限を設定
  • リサイズ監視が必要な要素を最小限にする
  • コンポーネント設計時にリサイズ連鎖を考慮
js
const useSafeResizeObserver = (ref, callback) => {
  useEffect(() => {
    if (!ref.current) return;

    const observer = new ResizeObserver(([entry]) => {
      // 要素がDOMに存在することを常に確認
      if (!ref.current) return;
      
      const { width, height } = entry.contentRect;
      callback({ width, height });
    });

    observer.observe(ref.current);
    return () => observer.disconnect();
  }, [ref, callback]);
};

最終的な判断指針

  1. 本番環境では無視してよい警告か確認
  2. UIコンポーネントの設定を調整
  3. リサイズ処理にデバウンス/スロットルを導入
  4. 不要な監視を解除するクリーンアップ処理を実装

効果的に対策することで、開発体験を改善しつつ、アプリケーションの安定性を高められます。