ResizeObserverループエラー修正
問題の本質
ResizeObserver loop completed with undelivered notifications
エラーは、要素のリサイズを監視するResizeObserver APIが、ブラウザの描画サイクル内でレイアウト変更が連鎖的に発生し、通知を正常に配信できなかった場合に発生します。Reactアプリケーションでのモーダル操作後や特定のUIコンポーネント使用時に頻発します。
エラーの発生原因
主な根本原因は以下のいずれかです:
- ブラウザ拡張機能の干渉(LastPass、LanguageToolなど)
- コンポーネントの動的サイズ変更ループ(無限リサイズサイクル)
- 特定UIライブラリのバグや設定不備(Material UI, Ant Designなど)
- 複数のリサイズイベントの競合
以下に実証済みの解決策をカテゴリ別に紹介します。
解決策1: ブラウザ拡張機能を無効化
最初に確認すべき対策
多くのケース(特にreact-router
v6移行後)で、パスワードマネージャーや文法チェッカー拡張機能がトリガーになります。最も効果的な初期対策です。
- LastPass、LanguageToolなどの拡張機能を一時無効化
- エラーが消えるか確認
- 特定の拡張機能を特定できたら、サイトで除外設定を追加
// 緊急避難的な対策(本番環境では非推奨)
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対応
multiline
やfullWidth
使用時の修正例:
<TextField
multiline
fullWidth // 問題が発生する場合はコメントアウト
label="説明"
sx={{
"& textarea": {
minHeight: "100px" // 高さを固定してリサイズループ防止
},
width: "99%" // fullWidth使用時は99%に変更
}}
/>
Ant DesignのTableコンポーネント
scroll
プロパティが原因の場合:
<Table
// scroll={{ x: "max-content" }} // エラー発生時は削除
dataSource={data}
columns={columns}
/>
解決策3: ResizeObserverの実装改善
リクエストアニメーションフレーム利用
レンダリングタイミングを最適化:
const observer = new ResizeObserver(entries => {
// ブラウザの描画サイクルに合わせて実行
window.requestAnimationFrame(() => {
if (!entries || entries.length === 0) return;
// リサイズ処理実装例
const { width, height } = entries[0].contentRect;
console.log(`新しいサイズ: ${width}x${height}`);
});
});
デバウンス機能の実装
複数のリサイズイベントをまとめる:
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
でエラーハンドリングを調整:
module.exports = {
devServer: {
client: {
overlay: {
runtimeErrors: (error) => {
// このエラーのみコンソールに転送
if (error.message.includes('ResizeObserver')) {
console.error('ResizeObserverエラー:', error);
return false; // オーバーレイ非表示
}
return true; // その他エラーは表示
},
},
},
},
};
最小幅の指定
CSSで要素サイズを安定化:
body, .resize-target {
min-width: 400px; /* 予期しない縮小を防止 */
}
根本原因と予防策
ResizeObserverの動作原理上、以下の条件でエラーが発生します:
- 要素Aのリサイズ → 要素Bのレイアウト変更
- 要素Bの変更 → 要素Aの再リサイズ
- このループがブラウザの制限値(通常5ループ)を超える
予防的対策例:
min-height
/min-width
で要素サイズの下限を設定- リサイズ監視が必要な要素を最小限にする
- コンポーネント設計時にリサイズ連鎖を考慮
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]);
};
最終的な判断指針
- 本番環境では無視してよい警告か確認
- UIコンポーネントの設定を調整
- リサイズ処理にデバウンス/スロットルを導入
- 不要な監視を解除するクリーンアップ処理を実装
効果的に対策することで、開発体験を改善しつつ、アプリケーションの安定性を高められます。