
useEffectフックの基本概念
useEffect
は、コンポーネントのレンダリング後に副作用(例:データ取得、タイマー設定、DOM操作)を処理するためのフックです。副作用とは、コンポーネントの状態やプロパティに依存しつつ、純粋なレンダリング以外の動作を指します。useEffect
の基本構文は以下の通りです。
import React, { useEffect } from 'react';
useEffect(() => {
// 副作用の処理
return () => {
// クリーンアップ処理(オプション)
};
}, [依存配列]);
useEffect
は、コールバック関数(副作用の処理)と依存配列を受け取ります。依存配列に指定した値が変更されたとき、または初回レンダリング時にコールバックが実行されます。依存配列が空([]
)の場合、初回レンダリング時のみ実行されます。クリーンアップ関数を返すことで、コンポーネントのアンマウント時や再実行前にリソースを解放できます。
ハンズオン:タイマーアプリケーションの作成
useEffect
の基本を理解するため、経過時間を表示するタイマーアプリケーションを作成します。第1回で作成したプロジェクト(my-react-app)のsrc/App.js
を以下のように編集します。
import React, { useState, useEffect } from 'react';
import './App.css';
function App() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setSeconds((prev) => prev + 1);
}, 1000);
return () => clearInterval(interval);
}, []);
return (
<div className="app-container">
<h1>タイマーアプリケーション</h1>
<p>経過時間: {seconds}秒</p>
</div>
);
}
export default App;
このコードでは、useState
でseconds
状態を管理し、useEffect
内でsetInterval
を使用して1秒ごとにseconds
を更新します。依存配列が空([]
)なので、タイマーはコンポーネントのマウント時(初回レンダリング)に開始されます。クリーンアップ関数でclearInterval
を呼び出し、コンポーネントのアンマウント時にタイマーを停止します。src/App.css
は第6回までのスタイルをそのまま使用します。
.app-container {
text-align: center;
padding: 20px;
font-family: Arial, sans-serif;
}
開発サーバー(npm start
)が起動している状態で保存すると、ブラウザに経過時間が秒単位で表示されます。ページをリロードしてもタイマーが継続的に動作し、コンポーネントを別の画面に切り替える(または開発サーバーを停止する)とクリーンアップが実行されることを確認できます。
APIからデータを取得する
useEffect
の一般的な用途は、外部APIからデータを取得することです。ここでは、JSONPlaceholderという公開APIを使用して、ユーザーデータを取得する例を試します。App.js
を以下のように変更します。
import React, { useState, useEffect } from 'react';
import './App.css';
function App() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users')
.then((response) => response.json())
.then((data) => {
setUsers(data);
setLoading(false);
})
.catch((error) => {
console.error('データ取得エラー:', error);
setLoading(false);
});
}, []);
return (
<div className="app-container">
<h1>ユーザーリスト</h1>
{loading ? (
<p>読み込み中...</p>
) : (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
)}
</div>
);
}
export default App;
このコードでは、fetch
を使用してJSONPlaceholderからユーザーデータを取得し、users
状態に保存します。loading
状態でデータ取得中のUIを管理し、取得完了後にユーザーの名前をリスト表示します。key
属性をuser.id
で指定し、リストレンダリングの効率を確保しています。App.css
にリストのスタイルを追加します。
ul {
list-style: none;
padding: 0;
}
li {
margin: 10px 0;
padding: 10px;
background-color: #f0f0f0;
border-radius: 5px;
max-width: 300px;
margin-left: auto;
margin-right: auto;
}
ブラウザで確認すると、最初に「読み込み中...」が表示され、データ取得後にユーザーの名前リストが表示されます。エラーハンドリングも含まれており、ネットワークエラーが発生した場合にコンソールにエラーが記録されます。
ハンズオン:副作用のカスタマイズ
useEffect
の柔軟性を体感するため、読者自身で機能を追加します。以下の課題を試してください。App.js
を編集し、ユーザーデータから特定のユーザー(例:IDが1のユーザー)のみを表示するボタンを追加します。以下は一例です。
import React, { useState, useEffect } from 'react';
import './App.css';
function App() {
const [users, setUsers] = useState([]);
const [selectedUser, setSelectedUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users')
.then((response) => response.json())
.then((data) => {
setUsers(data);
setLoading(false);
})
.catch((error) => {
console.error('データ取得エラー:', error);
setLoading(false);
});
}, []);
const showFirstUser = () => {
const firstUser = users.find((user) => user.id === 1);
setSelectedUser(firstUser);
};
return (
<div className="app-container">
<h1>ユーザーデータ</h1>
{loading ? (
<p>読み込み中...</p>
) : (
<>
<button onClick={showFirstUser}>ID:1のユーザーを表示</button>
{selectedUser ? (
<p>選択されたユーザー: {selectedUser.name}</p>
) : (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
)}
</>
)}
</div>
);
}
export default App;
このコードでは、ボタンクリックでIDが1のユーザーを表示し、選択されたユーザーがいればその情報だけを表示します。App.css
にボタンのスタイルを追加します。
button {
margin: 10px;
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
}
ブラウザで確認すると、ボタンをクリックすると特定のユーザーの名前が表示されます。自分で異なる条件(例:特定のユーザー名の検索)や表示項目(例:メールアドレス)を追加し、useEffect
の活用方法を試してください。
次のステップに向けて
本記事では、useEffect
フックを使用して副作用を管理し、タイマーやAPIデータ取得を実装しました。useEffect
は、外部リソースとの連携やライフサイクル管理に不可欠なツールです。第8回では、フォームの構築に焦点を当て、制御されたコンポーネントを使用してユーザー入力を効率的に処理する方法を学びます。これにより、ユーザーとの対話性をさらに強化できます。