・外部APIを取得する際の注意点
こんにちは、フロントエンドエンジニアのてりーです。
React + TypeScriptを5年以上使い続け、派遣 → フリーランス → メガベンチャーとキャリアを積んできました。
詳しいキャリアや学習ロードマップについてはこちらからどうぞ!
👉 本記事ではReact Hooksの中でも特に重要なuseEffect
に焦点を当てて解説します!
1. useEffectとは
useEffect
は、コンポーネントを外部システムと同期させるための React フックです。
useEffectの特徴は関数の実行タイミングを制御できることです。関数コンポーネントの処理タイミングに依存せず必要なタイミングで実行できるため、「副作用フック」とも呼ばれます。
主な用途
- データ取得(API通信)
- DOMの操作
- サブスクリプション(イベントリスナーの設定など)
例: ページが読み込まれたときにuseEffectを実行
import { useEffect } from 'react';
useEffect(() => {
console.log('コンポーネントがマウントされました');
}, []);
依存配列(Dependency Array)
- 空配列
[]
: マウント時のみ実行 - 変数を指定
[state]
: 変数が更新されるたびに実行
ReactとTypeScriptを基礎から習得したい方は、こちらもチェック!
👉 【2025年】未経験から即戦力へ!React+TypeScriptの学習ロードマップ
2. useEffectを使ったAPI通信の基本
2.1 基本形
useEffect
を使ってAPIからデータを取得する基本例です。
import { useState, useEffect } from 'react';
function App() {
const [data, setData] = useState(null);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/posts/1')
.then((res) => res.json())
.then((json) => setData(json))
.catch((error) => console.error('Error fetching data:', error));
}, []);
return (
<div>
{data ? <h1>{data.title}</h1> : <p>Loading...</p>}
</div>
);
}
2.2 解説
1. 初回マウント時にAPIを実行
依存配列を []
にすることで、初回マウント時のみ実行されます。
2. 取得したデータをuseStateで管理
fetch('https://jsonplaceholder.typicode.com/posts/1')
.then((res) => res.json())
.then((json) => setData(json))
.catch((error) => console.error('Error fetching data:', error));
3. エラーハンドリング
失敗時は catch
でログやUIへ反映します。
フロントエンドのAPI知識を整理したい方は、こちらもチェック!
👉 フロントエンドエンジニアのためのHTTP・APIガイド
3. useEffectの実装でよくあるエラーと対処
3.1 無限ループ:依存配列の指定漏れ
useEffect(() => {
fetchData();
}); // ⚠️ 無限ループの原因
解決策
useEffect(() => {
fetchData();
}, []); // ✅ 依存配列を追加
3.2 クリーンアップ漏れ:通信が中断されずエラーに
useEffect(() => {
const controller = new AbortController();
fetch('https://api.example.com/data', { signal: controller.signal });
return () => controller.abort();
}, []);
より実践的な例
useEffect(() => {
const controller = new AbortController();
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data', { signal: controller.signal });
if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`);
const result = await response.json();
console.log('取得したデータ:', result);
} catch (err) {
if (err.name === 'AbortError') {
console.warn('API通信が中断されました:', err.message);
} else if (err.name === 'TypeError') {
console.error('ネットワークエラーが発生:', err.message);
} else {
console.error('予期しないエラー:', err.message);
}
} finally {
console.log('API通信が完了または中断');
}
}
fetchData();
return () => {
console.log('API通信を中断します');
controller.abort();
};
}, []);
実践的なプロダクトを作りながらReactを学びたい方へ!
👉 【React+TypeScript】Netflixのクローンを作るチュートリアル
👉 【React Hooks入門】useStateで買い物リストを作るチュートリアル
4. 最新トレンド:Axios / React Query
4.1 AxiosでのAPI通信
Axiosはfetch
に比べ直感的で、エラーハンドリングやインターセプターが便利です。
通信例
import axios from 'axios';
import { useEffect, useState } from 'react';
function App() {
const [data, setData] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const controller = new AbortController();
async function fetchData() {
try {
setLoading(true);
const response = await axios.get('https://api.example.com/data', {
signal: controller.signal,
});
setData(response.data);
} catch (err) {
if (axios.isCancel(err)) {
console.warn('API通信が中断されました:', err.message);
} else {
console.error('API通信エラー:', err.message);
setError(err);
}
} finally {
setLoading(false);
}
}
fetchData();
return () => controller.abort();
}, []);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<div>
{data ? <pre>{JSON.stringify(data, null, 2)}</pre> : <p>No data available</p>}
</div>
);
}
export default App;
インターセプターの例
import axios from 'axios';
axios.interceptors.request.use(
(config) => {
console.log('リクエスト送信:', config.url);
return config;
},
(error) => Promise.reject(error)
);
axios.interceptors.response.use(
(response) => {
console.log('レスポンス受信:', response.status);
return response;
},
(error) => Promise.reject(error)
);
4.2 React QueryでのAPI通信
React Query(現TanStack Query)は、キャッシュや自動再フェッチ、状態管理を一手に担うライブラリです。
TanStack Query (formerly known as React Query) is often desc…
基本例
import { useQuery, QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
<DataFetchingComponent />
</QueryClientProvider>
);
}
function DataFetchingComponent() {
const { data, error, isLoading } = useQuery({
queryKey: ['data'],
queryFn: async () => {
const res = await fetch('https://api.example.com/data');
if (!res.ok) throw new Error('データ取得に失敗しました');
return res.json();
},
});
if (isLoading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<div>
<h1>データ取得成功!</h1>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
);
}
export default App;
自動再フェッチ
const { data, error, isLoading } = useQuery({
queryKey: ['data'],
queryFn: async () => {
const res = await fetch('https://api.example.com/data');
return res.json();
},
refetchOnWindowFocus: true, // フォーカス時に自動再フェッチ
});
5. まとめ:ReactでAPI通信を効率化するコツ
- useEffectを適切に使う:依存配列を正しく設定し、不要な再レンダリングを防ぐ。
- クリーンアップで中断:
AbortController
を使いアンマウント時に通信中断。 - Axios / React Queryを活用:規模や要件に合わせて選択。大規模はReact Queryが便利。
React関連の記事
👉 【2025年】未経験から即戦力へ!React+TypeScriptの学習ロードマップ
👉 【React+TypeScript】Netflixのクローンを作るチュートリアル
👉 【 React Hooks入門】useStateで買い物リストを作るチュートリアル
人気記事
👉 未経験の僕がメガベンチャーエンジニアになった軌跡
👉 エンジニア転職を成功させる
👉 【転職ドラフト指名の画像アリ】2年目で600万の指名を獲得した理由
👉 フルリモート週2~3日からでも副業が出来るエージェント紹介