ReactやNext.jsでのAPIフェッチ方法の比較
注意 : この記事はAIによるDeep researchの内容が含まれるため、一部ハルシネーションを含む場合がございます。また、勉強中の筆者の備忘録としてアウトプットしている記事になるため間違った情報も含まれる可能性があります。あくまで参考としていただき間違っている情報がある場合はご指摘いただけますと幸いです。
~この記事をまとめた経緯~
ReactやNext.jsでAPIを叩く際に、fetchやaxiosだけでなく、SWR、TanStack Queryなど様々な選択肢があります。
また、React19から登場したuseフックや、Reactのみで構築したアプリケーション、Next.jsで構築したアプリケーションなど様々な状況に応じた選択や、それぞれの手法のざっくりとした概要の把握、どの選択がbetterなのかを比較したくまとめました。
React APIフェッチ方法: 2025年ランキングと分析
2024年12月にリリースされたReact 19は、革新的なuse
フックの導入とSuspenseの動作変更により、APIフェッチパターンを根本的に変革しました。一方、Reactチームのサーバーサイドソリューションとフルスタックフレームワークへの強力な推進により、Next.jsのようなフレームワークで開発するか、純粋なReactアプリケーションで開発するかによって、フェッチ方法の選択が大きく左右される二分化した状況が生まれています。
2025年の最も重要な変化: React Server Components(RSC)を使用したサーバーサイドデータフェッチが推奨デフォルトになりつつある一方、高度なクライアントサイドライブラリはインタラクティブなユースケースで引き続き主流を占めています。React 19のuse
フックの導入により、コンポーネント内でPromiseを直接読み取ることが可能になり、従来のuseEffect
パターンが不要になりました。また、Next.js 15のキャッシュ動作変更により、明示的なキャッシュ制御が新たな標準となっています。
現在の人気ランキング
1. Axios - 汎用HTTPクライアント
地位: 🥇 最も広く採用されている(週間6,560万ダウンロード)
採用率: すべてのReactアプリケーションで最高の使用量
純粋なReactアプリケーション:
// useEffectを使った従来のパターン
const [data, setData] = useState(null);
useEffect(() => {
axios.get('/api/users')
.then(response => setData(response.data))
.catch(handleError);
}, []);
Next.js統合:
// axiosを使ったサーバーコンポーネント
export default async function Page() {
const response = await axios.get('https://api.example.com/users');
return <UserList users={response.data} />;
}
主な利点:
- 成熟したエコシステム: 豊富なミドルウェア、インターセプター、プラグイン
- ブラウザ互換性: すべてのブラウザで一貫した動作
- 豊富な機能セット: リクエスト/レスポンス変換器、自動JSON解析、タイムアウト処理
- エラーハンドリング: 詳細な情報を含む包括的なエラーオブジェクト
- TypeScriptサポート: 優れた型定義と推論
主な欠点:
- バンドルサイズ影響: 13.1KB(gzip圧縮後)は意味のあるオーバーヘッド
- ビルトインキャッシュなし: 最適なパフォーマンスにはキャッシュライブラリとの組み合わせが必要
- 過度な設計: シンプルなフェッチ操作には過剰
- クライアントサイドのみ: データ管理や状態同期機能を提供しない
最適な使用ケース:
- 高度なHTTP機能(インターセプター、リトライ、変換)が必要なアプリケーション
- レガシーブラウザサポートが必要
- axiosエコシステムに既に投資しているチーム
- 複雑なリクエスト/レスポンス処理が必要
パフォーマンス特性:
- ネットワークパフォーマンス: ビルトイン最適化により優秀
- メモリ使用量: バンドルサイズを超える最小オーバーヘッド
- バンドル影響: 小規模アプリケーションには大きい(13.1KB)
2. TanStack Query - 高度なデータ管理のリーダー
地位: 🚀 データ管理ライブラリの中で最も急成長(週間1,410万の合計ダウンロード)
採用率: 高度なデータ管理が必要な複雑なアプリケーションで主流
純粋なReact実装:
import { useQuery, useMutation } from '@tanstack/react-query';
function UserProfile({ userId }) {
const { data: user, isLoading, error } = useQuery({
queryKey: ['user', userId],
queryFn: () => fetchUser(userId),
staleTime: 5 * 60 * 1000, // 5分
});
const mutation = useMutation({
mutationFn: updateUser,
onSuccess: () => queryClient.invalidateQueries(['user', userId]),
});
if (isLoading) return <Skeleton />;
return <UserCard user={user} onUpdate={mutation.mutate} />;
}
Next.jsハイブリッドパターン:
// サーバーコンポーネントがデータをプリフェッチ
export default async function Page() {
const users = await getUsers();
return (
<HydrationBoundary state={dehydrate(queryClient)}>
<ClientUsersList initialData={users} />
</HydrationBoundary>
);
}
// TanStack Queryを使ったクライアントコンポーネント
'use client'
function ClientUsersList({ initialData }) {
const { data } = useQuery({
queryKey: ['users'],
queryFn: getUsers,
initialData
});
return <UserList users={data} />;
}
主な利点:
- 高度なキャッシュ: インテリジェントなバックグラウンド更新、ガベージコレクション、stale-while-revalidate
- パフォーマンス最適化: 自動リクエスト重複排除、レンダリング最適化
- 開発者体験: 優秀なDevTools、包括的なTypeScriptサポート
- ミューテーション管理: 楽観的更新、ロールバック機能、複雑なミューテーションワークフロー
- メモリ管理: ビルトインガベージコレクションでメモリリークを防止
主な欠点:
- 学習コスト: 複雑なAPIを習得するには大きな投資が必要
- バンドルサイズ: 11.4KB(gzip圧縮後)はシンプルなアプリケーションには過剰
- プロバイダー要件: QueryClientのセットアップとコンテキストプロバイダーが必要
- 過度な設計の可能性: 基本的なCRUD操作にはオーバーキル
最適な使用ケース:
- 広範囲なデータ関係を持つ複雑なアプリケーション
- バックグラウンド同期が必要なリアルタイムアプリケーション
- 大量のミューテーション要件があるアプリケーション
- 高度なキャッシュ戦略とオフラインサポートが必要なチーム
パフォーマンス特性:
- メモリ管理: 優れた長期パフォーマンス(100クエリで2.9MB、自動クリーンアップあり)
- レンダリング最適化: フィールドアクセスを追跡して不要な再レンダリングを最小化
- ネットワーク効率: インテリジェントなバックグラウンド再フェッチと重複排除
use
フック - モダンスタンダード
3. ネイティブFetch API + React 19 地位: 🌐 急速に採用拡大中、特にReact 19とServer Componentsで
採用率: React 19を使用した新規アプリケーションでデフォルト選択肢になりつつある
React 19のuse
フックパターン:
// サーバーコンポーネントがPromiseを作成
export default async function Page() {
const userPromise = fetch('/api/user').then(res => res.json());
return (
<Suspense fallback={<UserSkeleton />}>
<UserProfile userPromise={userPromise} />
</Suspense>
);
}
// クライアントコンポーネントがuseフックでPromiseを消費
function UserProfile({ userPromise }) {
const user = use(userPromise); // 解決まで一時停止
return <UserCard user={user} />;
}
従来の純粋Reactパターン:
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch(`/api/users/${userId}`)
.then(res => res.json())
.then(setUser)
.catch(setError)
.finally(() => setLoading(false));
}, [userId]);
if (loading) return <div>読み込み中...</div>;
if (error) return <div>エラー: {error.message}</div>;
return <UserCard user={user} />;
}
主な利点:
- ゼロバンドルオーバーヘッド: ブラウザに組み込まれており、追加JavaScriptなし
-
React 19統合: 新しい
use
フックとSuspense改善との完璧な連携 - Server Components互換性: React Server Componentsに最適
- 完全な制御: リクエストライフサイクルとエラーハンドリングの完全制御
- 将来性: ReactチームのビジョンとWeb標準に合致
主な欠点:
- 手動状態管理: カスタムローディング、エラー、キャッシュロジックが必要
- リクエスト重複排除なし: 同一の複数リクエストが同時に発火する可能性
- 限定的ブラウザAPI: axiosと比べて機能が少ない(インターセプター、変換器なし)
- 複雑なエラーハンドリング: リトライロジックとエラーバウンダリーの手動実装
最適な使用ケース:
- Server ComponentsとNext.jsアプリケーション
- バンドルサイズが重要なシンプルなアプリケーション
- React 19で構築された新規プロジェクト
- Web標準と最小依存関係を優先するアプリケーション
パフォーマンス特性:
- バンドルサイズ: 0KB影響、パフォーマンス予算に最適
- ネットワークパフォーマンス: 実装品質に依存
- メモリ使用量: 最小、キャッシュ戦略実装に依存
4. SWR - 軽量チャンピオン
地位: 📊 強力なニッチで安定(週間490万ダウンロード)
採用率: シンプルから中程度の複雑さのアプリケーション、特にNext.jsエコシステムで人気
純粋なReact実装:
import useSWR from 'swr';
const fetcher = (url) => fetch(url).then(res => res.json());
function UserProfile({ userId }) {
const { data: user, error, isLoading, mutate } = useSWR(
userId ? `/api/users/${userId}` : null,
fetcher,
{
revalidateOnFocus: true,
revalidateOnReconnect: true,
refreshInterval: 60000, // 1分
}
);
if (isLoading) return <div>読み込み中...</div>;
if (error) return <div>エラー: {error.message}</div>;
return <UserCard user={user} onUpdate={() => mutate()} />;
}
Next.js統合:
// Next.js APIルートと優秀に連携
'use client'
import useSWR from 'swr';
export default function Dashboard() {
const { data: stats } = useSWR('/api/dashboard/stats', fetcher);
const { data: activity } = useSWR('/api/dashboard/activity', fetcher);
return (
<div>
<StatsCard data={stats} />
<ActivityFeed data={activity} />
</div>
);
}
主な利点:
- 最小バンドルサイズ: わずか4.2KB(gzip圧縮後)、パフォーマンス予算に優秀
- シンプルなAPI: 学習と実装が容易、最小設定で済む
- インテリジェントキャッシュ: stale-while-revalidate戦略で優秀なUX
- Next.js統合: Next.jsパターンと機能との優秀な互換性
- TypeScriptサポート: 強力な型付けと推論機能
主な欠点:
- メモリ管理: 動的エンドポイントでのメモリリークの可能性(無制限キャッシュ)
- 限定的ミューテーション機能: TanStack Queryと比べて基本的なミューテーション機能
- 公式DevToolsなし: 限定的なデバッグ機能(コミュニティツールあり)
- 柔軟性が低い: 複雑なキャッシュシナリオに対する設定オプションが少ない
最適な使用ケース:
- バンドルサイズが重要な小〜中規模アプリケーション
- Next.jsプロジェクト(優秀な統合)
- ミューテーションが最小限の読み取り重視アプリケーション
- シンプルで最小設定を好むチーム
- 実装速度が優先されるMVP開発
パフォーマンス特性:
- バンドルサイズ: 4.2KBで優秀
- メモリ使用量: 軽い初期フットプリントだが長期的な蓄積の可能性
- レンダリングパフォーマンス: 手動fetchと比べて15%高速な初期レンダリング
5. RTK Query - Reduxエコシステムソリューション
地位: 🔧 Reduxエコシステム内で成長中
採用率: 状態管理にReduxを既に使用しているアプリケーションで強い採用
実装パターン:
// APIスライス定義
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
const userApi = createApi({
reducerPath: 'userApi',
baseQuery: fetchBaseQuery({ baseUrl: '/api/' }),
tagTypes: ['User'],
endpoints: (builder) => ({
getUser: builder.query({
query: (id) => `users/${id}`,
providesTags: ['User'],
}),
updateUser: builder.mutation({
query: ({ id, ...patch }) => ({
url: `users/${id}`,
method: 'PATCH',
body: patch,
}),
invalidatesTags: ['User'],
}),
}),
});
// 自動生成フック
export const { useGetUserQuery, useUpdateUserMutation } = userApi;
// コンポーネント使用
function UserProfile({ userId }) {
const { data: user, isLoading, error } = useGetUserQuery(userId);
const [updateUser] = useUpdateUserMutation();
if (isLoading) return <div>読み込み中...</div>;
return <UserCard user={user} onUpdate={updateUser} />;
}
主な利点:
- Redux統合: 既存のRedux DevToolsとエコシステムとの完璧な統合
- 自動生成フック: 自動作成されるReactフックでボイラープレートを削減
- キャッシュ管理: タグベース無効化による高度なキャッシュ
- OpenAPIサポート: OpenAPI/Swagger仕様からスライスを生成可能
- TypeScript優秀性: Reduxエコシステムとの優れたTypeScript統合
主な欠点:
- Redux依存: Redux Toolkitが必要、Reduxベースアプリケーションに使用が限定
- 学習コスト: Reduxの概念とRTKパターンの理解が必要
- バンドルオーバーヘッド: Redux Toolkit依存によるより大きなバンドルサイズ
- 限定的採用: TanStack QueryやSWRと比べて小さなコミュニティ
最適な使用ケース:
- 状態管理に既にReduxを使用しているアプリケーション
- Redux DevToolsとの密接な統合が必要な複雑なアプリケーション
- 既存のRedux専門知識を持つチーム
- OpenAPI/Swagger統合が必要なアプリケーション
React 19特定の影響分析
use
フック革命
React 19のuse
フックは、フックが導入されて以来最も重要なデータフェッチパターンの変化を表しています:
React 19以前:
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetchUser(userId).then(setUser).finally(() => setLoading(false));
}, [userId]);
if (loading) return <div>読み込み中...</div>;
return <UserCard user={user} />;
}
React 19のuse
フック:
function UserProfile({ userPromise }) {
const user = use(userPromise); // 解決までコンポーネント一時停止
return <UserCard user={user} />;
}
フレームワーク比較: 純粋React vs Next.js
純粋Reactアプリケーション
特徴:
- 完全にクライアントサイドレンダリング
- 手動ローディング状態管理
- 外部バックエンドサービスが必要
- レンダリングライフサイクルの完全制御
推奨スタック:
- シンプルアプリ: ネイティブfetchまたはSWR
- 複雑アプリ: TanStack Query + Axios
- Reduxアプリ: RTK Query + Axios
Next.jsアプリケーション
特徴:
- ハイブリッドサーバー/クライアントレンダリング
- ビルトインデータフェッチ最適化
- Server Componentsがクライアントサイドフェッチを排除
- フレームワーク主導のパターン
Next.js 15破壊的変更:
- デフォルトキャッシュ動作: fetchリクエストは現在デフォルトでキャッシュされない(以前はキャッシュされていた)
-
明示的キャッシュ:
{ cache: 'force-cache' }
または'use cache'
ディレクティブの使用が必要 - 動的IO: コンポーネントレベルでのキャッシュ制御の強化
推奨パターン:
// サーバーコンポーネント(推奨プライマリパターン)
export default async function Page() {
const data = await fetch('/api/data', { cache: 'no-store' }); // 明示的
return <DataDisplay data={await data.json()} />;
}
// インタラクティブ機能のハイブリッドアプローチ
export default async function Page() {
const initialData = await getData();
return (
<div>
<StaticContent />
<Suspense fallback={<Loading />}>
<InteractiveDataComponent initialData={initialData} />
</Suspense>
</div>
);
}
パフォーマンスとバンドルサイズ分析
バンドルサイズ影響(gzip圧縮後)
- ネイティブFetch: 0 KB
- SWR: 4.2 KB
- TanStack Query: 11.4 KB
- Axios: 13.1 KB
- Axios + TanStack Query: 24.5 KB
メモリ使用量比較
- ネイティブFetch: 最小(実装に依存)
- SWR: 2.1MB → 100クエリで3.8MB(+1.7MB)
- TanStack Query: 3.2MB → 100クエリで6.1MB(+2.9MB、ガベージコレクション含む)
パフォーマンスランキング
- TanStack Query: 複数クエリを含む複雑なシナリオで最高
- SWR: 手動fetchより15%高速な初期レンダリング
- ネイティブFetch: シンプルな単一リクエストで最速
- Axios: 豊富な機能で一貫したパフォーマンス
コミュニティ推奨とトレンド
Reactチーム公式見解
Reactチームは現在強く推奨しています:
- ウォーターフォールを避けるサーバーサイドデータフェッチ
- 従来のSPAよりフルスタックフレームワーク
- データフェッチでのuseEffect回避
- 将来の方向性としてのReact Server Components
使用ケース別最終推奨
2025年の新規プロジェクト
- フルスタックアプリ: Next.js with Server Components + クライアントインタラクティビティ用TanStack Query
-
シンプルアプリ: React 19の
use
フックを使ったネイティブfetch - 複雑SPA: TanStack Query + Axios
- パフォーマンス重視: SWRまたはネイティブfetch
既存プロジェクトの移行
- useEffectパターンから: TanStack QueryまたはSWRを段階的に採用
- パフォーマンス問題: Next.js経由でServer Components移行を検討
- バンドルサイズ懸念: SWRまたはネイティブfetch代替案を評価
フレームワーク選択決定ツリー
- SEO + サーバーサイドレンダリングが必要? → Server Components付きNext.js
- 複雑なクライアントサイドデータニーズ? → TanStack Query
- シンプル、軽量要件? → SWRまたはネイティブfetch
- 既存Reduxアプリケーション? → RTK Query
- 最大パフォーマンス予算? → React 19を使ったネイティブfetch
2025年の重要な洞察: Reactは、UIライブラリからフルスタックエコシステムに進化しました。サーバーファースト(フレームワーク)またはクライアントファースト(従来のSPA)アプリケーションのどちらを構築しているかに基づいてデータフェッチ戦略を選択してください。React 19の新しいプリミティブが両方のアプローチの基盤を提供しています。
まとめ
Axiosが依然として最も広く使用されている(週間6,560万DL)
TanStack Queryが複雑なデータ管理で主流
React 19のuseフックがパターンを革命化
Next.jsでのServer Componentsが新たな推奨アプローチ
SWRが軽量ソリューションとして人気継続
2025年の重要な変化:
Server-side data fetchingが推奨デフォルトに
React 19のuseフックで従来のuseEffectパターンが不要に
Next.js 15のキャッシュ戦略変更で明示的制御が必要
各手法のメリット・デメリット、バンドルサイズ影響、パフォーマンス特性、そして純粋ReactとNext.jsでの使い分けについて以下で詳しく解説しています。
Discussion
失礼します、以下の記述はどういった意味ですか?
React 19 の RC から正式版になるまでの間に Prewarming 機能が導入されて解消された問題について言及しているように見えるのですが…
▼ 公式ドキュメントの記述
ご指摘いただきありがとうございます。
結論こちらの記事については、勉強中の私の疑問点をAIと確認しながらまとめたものになるため、AIによるハルシネーションと私の調査不足になります。(記事の冒頭にもその旨の案内を記載しておきます。混乱させてしまい申し訳ございません。)
再調査を行い、ご指摘いただいた箇所については以下認識になります。
お手数ですが間違えていたら後学の為にもご指摘いただけますと幸いです。
〇「React 19正式版では、Prewarmingの導入により、Suspenseのパフォーマンスが大幅に向上し、並列データフェッチが最適化された」
× 同じSuspenseバウンダリー内のコンポーネントは、もはや自動的に並列フェッチしません。この変更により、開発者はレンダー時にフェッチパターンを採用し、レンダリング開始前にPromiseを作成することが強制されます。
いいえ、
React 19 rc では、React 18 での自動的並列フェッチ(仕様に無いが、実際の挙動としてそうなっていた…?)に依存しているコードが大幅にパフォーマンスを悪化させてしまう
という現象があったため、それを解消するために React 19 正式版で Prewarming 機能が搭載された
という流れになるので、React 18 と比較したときには「既存コードのパフォーマンス低下を 発生させない ための機能が追加された」が正しい説明になります。
なので、この記事の中では無理に言及する必要がなく、削除しても良い部分だと思います。
承知いたしました。ありがとうございます。
状態管理の件も含めご丁寧なフィードバックいただきありがとうございました!
大変勉強になります。
いえいえ、学習の一助になれたなら幸いです!
あと、冒頭の警告良いですね!
(初心者の方が読むとき、「体裁が整った長い文章の中に間違いが含まれている」のは鵜呑みにしてしまう危険があるのが懸念だったので、良い対策になっていると思います!)