React 18のSuspense完全対応ガイド:並列レンダリング時代の新常識

React 18でついに本格実装されたSuspenseは、フロントエンド開発における非同期UIの扱いを大きく変える存在です。
とくに Concurrent Rendering(並列レンダリング) と組み合わせることで、ユーザー体験を損なうことなくデータ読み込みを含むUIを柔軟に設計できるようになりました。
本記事では、React 18のSuspenseに関する全体像と活用方法を、サンプルコードと公式ドキュメントを交えながら丁寧に解説いたします。
Suspenseの役割と進化
React 18以前でもReact.lazy()
と組み合わせてコード分割に使うことは可能でした。
しかしReact 18からは データフェッチ や サーバーサイドレンダリング(SSR) にも活用できるよう拡張され、並列レンダリングと組み合わせた実用的な非同期UI構築が実現します。
バージョン | Suspenseの用途 | 備考 |
---|---|---|
React 16.6 | React.lazy() によるコード分割 | クライアント限定 |
React 18 | データフェッチ、SSRまで対応 | サーバー・クライアント両方 |
公式ドキュメント:React Suspense
Suspenseの基本構文と使い方
最も基本的な使い方はReact.lazy()
と組み合わせて、遅延ロードされるコンポーネントの読み込み中にFallbackを表示する方法です。
tsximport React, { Suspense } from 'react';
const LazyComponent = React.lazy(() => import('./MyComponent'));
function App() {
return (
<Suspense fallback={<div>読み込み中...</div>}>
<LazyComponent />
</Suspense>
);
}
上記のように、fallback
にローディング中のプレースホルダーUIを設定することで、スムーズな体験を提供できます。
データフェッチとの統合:use()フックとServer Component
React 18ではuse()
フックとSuspense
を組み合わせることで、データフェッチの非同期処理も同様に扱えるようになりました。
Server Componentと組み合わせた形での使用が推奨されます。
tsx// app/page.tsx
import { Suspense } from 'react';
function PostList() {
const posts = use(fetch('https://jsonplaceholder.typicode.com/posts').then(res => res.json()));
return (
<ul>
{posts.map((post) => <li key={post.id}>{post.title}</li>)}
</ul>
);
}
export default function Page() {
return (
<Suspense fallback={<div>投稿を取得中...</div>}>
<PostList />
</Suspense>
);
}
このようにuse()
フックを通してPromiseを直接扱うことで、非同期の状態をSuspenseで待たせることができます。
公式ドキュメント:React use()
並列レンダリングとTransition APIの活用
React 18の最大の特徴は並列レンダリング(Concurrent Rendering)です。
startTransition()
を使うことで、低優先度のUI更新をユーザー操作とは切り離して扱うことが可能になります。
tsximport { useState, startTransition } from 'react';
function SearchInput({ onSearch }) {
const [input, setInput] = useState('');
const handleChange = (e) => {
const value = e.target.value;
setInput(value);
startTransition(() => {
onSearch(value);
});
};
return <input value={input} onChange={handleChange} />;
}
検索のように頻繁な再描画が発生するケースでは、startTransition()を用いることでUXが大きく改善されます。
公式ガイド:React startTransition
Suspenseのネスト構造と複数待機UIの設計
Suspenseは入れ子構造で使用することで、個別の読み込み状態に応じて異なるfallbackを提供できます。
tsxfunction App() {
return (
<Suspense fallback={<div>ページ全体を読み込み中...</div>}>
<Header />
<Suspense fallback={<div>コンテンツを読み込み中...</div>}>
<MainContent />
</Suspense>
<Footer />
</Suspense>
);
}
ネストされたSuspense
はそれぞれの非同期処理が完了するタイミングで段階的に描画されるため、体感速度が向上します。
Suspenseでのエラーハンドリング:ErrorBoundaryとの併用
SuspenseではPromiseの失敗による例外をErrorBoundary
で補足できます。
tsxclass MyErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError(error) {
return { hasError: true };
}
render() {
if (this.state.hasError) {
return <div>エラーが発生しました</div>;
}
return this.props.children;
}
}
tsxfunction App() {
return (
<MyErrorBoundary>
<Suspense fallback={<div>Loading...</div>}>
<ComponentWithError />
</Suspense>
</MyErrorBoundary>
);
}
こうすることで、非同期フェッチやモジュール読み込み失敗時のフォールバックUIを明示的に表示できます。
エラー処理の公式ガイド:Error Boundaries
React 18でのSuspenseとStreaming SSRの統合
React 18ではサーバー側で非同期処理を待ちながら段階的にHTMLをストリーミング出力する機能が追加されています。
tsximport { renderToPipeableStream } from 'react-dom/server';
function handleRequest(req, res) {
const stream = renderToPipeableStream(<App />, {
onShellReady() {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/html');
stream.pipe(res);
},
});
}
Streaming SSRでは、Suspense
が途中で止める場所を制御し、ページ全体を一気に表示せず段階的に描画できます。
詳細はこちら:React Server Rendering
React 18とSuspenseのベストプラクティス
React 18でSuspenseを利用する際のベストプラクティスをまとめます。
項目 | 内容 |
---|---|
フォールバックUI | 適切な場所に、適切な粒度で設定する |
エラーハンドリング | ErrorBoundary との併用を推奨 |
ネスト構造の活用 | スケルトンローディングと段階的描画に有効 |
Streaming SSR | ユーザーに早く表示される体験を提供できる |
非同期ロジック | クライアント側ではuseEffect で処理を分離 |
よくある疑問とその回答
Q. Suspenseはクライアントでも使えますか?
はい。従来どおりReact.lazy()
によるコード分割では使えますが、データフェッチのような用途にはサーバー環境が適しています。
Q. API呼び出しをuse()
で行うには?
use()
はサーバーコンポーネント内でPromiseの解決を待つために使います。クライアント側では使用できません。
Q. ReduxやSWRとの違いは?
SuspenseはあくまでUIの非同期待機ロジックであり、状態管理ライブラリと役割が異なります。組み合わせて使うのが理想です。
まとめ:SuspenseはReactの未来を支える基盤
React 18におけるSuspenseは、「非同期処理の待機をUIで表現する」ための汎用的な仕組みとして再定義されました。
並列レンダリング、Streaming SSR、Server Componentと組み合わせることで、これまで実現が難しかった待たせないUX、スケーラブルな描画制御、適応型のデータ取得が可能になります。
フロントエンド開発者にとっては避けて通れない知識となるSuspense。今後のReact開発においては、その理解と活用がプロダクト品質を大きく左右する鍵になるでしょう。
記事Article
もっと見る- article
React Suspenseを使う際に避けたいアンチパターン5選と解決策について紹介
- article
React SuspenseとServer Componentsの融合:クライアントとサーバの役割分担
- article
Suspense + useTransitionで滑らかなUXを実現するやり方を紹介
- article
React Suspenseでデータフェッチ!fetchでは動かない理由と正しい書き方について紹介
- article
Suspense × lazyで始めるコード分割:Reactアプリの初歩的最適化
- article
React Suspense入門:非同期UIを直感的に書ける新しいアプローチとは?