React 速習チュートリアル

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 />
);