React Suspense
1. Suspenseとは?
React Suspenseは、コードやデータの読み込みを待機している間に、代替となるHTML(フォールバック)を表示させるための機能です。
この代替HTMLには、コンポーネント、テキスト、または任意の有効なコンテンツを指定できます。
主なユースケースは以下の通りです:
- Suspenseに対応したフレームワークでのデータフェッチ(Data Fetching)
React.lazy()を使用したコンポーネントの動的インポート(Dynamic Import)
2. Suspenseの使用方法
コンポーネントの読み込みに時間がかかる場合、そのコンポーネントを Suspense でラップすることで、読み込み中に fallback プロパティに渡した内容を表示できます。
2.1 実装例
以下の例では、Fruits コンポーネントの読み込みに2秒かかると想定しています。そのため、読み込みが完了するまで「読み込み中...」というメッセージを表示するように Suspense でラップしています。
import { createRoot } from 'react-dom/client';
import { Suspense } from 'react';
import Fruits from './Fruits';
function App() {
return (
<div>
{/* 読み込みが完了するまで fallback の内容が表示される */}
<Suspense fallback={<div>読み込み中...</div>}>
<Fruits />
</Suspense>
</div>
);
}
createRoot(document.getElementById('root')).render(
<App />
);3. lazyロード(遅延読み込み)との併用
Suspense コンポーネントのもう一つの一般的な用途は、lazy ロードを使用してコンポーネントをインポートする場合です。
先ほどの例では、ローディングメッセージを確認するために意図的に2秒の遅延(擬似的な遅延)を発生させました。配列から3つのフルーツを表示するような単純なタスクは、通常一瞬で終わるため、ローディング画面を確認することは困難だからです。
しかし、lazy ロードを使用すれば、たとえ処理が高速であっても、コンポーネントを動的にインポートし、その読み込み中にローディングメッセージを表示させることができます。
3.1 lazyロードを使用しない場合(比較用)
この例は、読み込みが非常に速いため、ローディングメッセージがほとんど見えません。
import { createRoot } from 'react-dom/client';
import { Suspense } from 'react';
import Cars from './Cars';
function App() {
return (
<div>
<Suspense fallback={<div>読み込み中...</div>}>
<Cars />
</Suspense>
</div>
);
}
createRoot(document.getElementById('root')).render(
<App />
);3.2 lazyロードを使用する場合
同じ例を、lazy ロードを使用して実装すると以下のようになります。
import { createRoot } from 'react-dom/client';
import { Suspense, lazy } from 'react';
// lazy を使用してコンポーネントを動的にインポート
const Cars = lazy(() => import('./Cars'));
function App() {
return (
<div>
<Suspense fallback={<div>読み込み中...</div>}>
<Cars />
</Suspense>
</div>
);
}
createRoot(document.getElementById('root')).render(
<App />
);3.3 コードの解説
lazy(): コンポーネントを動的に読み込むことができます。Suspense: コンポーネントの読み込み中にフォールバック(代替UI)を表示します。
4. 複数のコンポーネントをまとめる
一つの Suspense コンポーネントで、複数の lazy コンポーネントをラップすることも可能です。
4.1 実装例
import { createRoot } from 'react-dom/client';
import { Suspense, lazy } from 'react';
// 各コンポーネントを lazy ロードで定義
const Header = lazy(() => import('./Header'));
const Content = lazy(() => import('./Content'));
const Sidebar = lazy(() => import('./Sidebar'));
function App() {
return (
<div>
{/* すべてのコンポーネントが揃うまで単一の fallback を表示 */}
<Suspense fallback={<div>読み込み中...</div>}>
<Header />
<div style={{ display: 'flex' }}>
<Sidebar />
<Content />
</div>
</Suspense>
</div>
);
}
createRoot(document.getElementById('root')).render(
<App />
);