React Hooksとは
Hooksは、React 16.8(2019年)で導入された機能で、関数コンポーネントで状態管理やライフサイクル処理を行うための仕組みです。
Hooksのメリット:
- クラスコンポーネントより簡潔で読みやすいコード
- ロジックの再利用がしやすい(カスタムHooks)
- thisの扱いを気にする必要がない
- コンポーネントの責務が明確になる
useState - 状態管理の基本
useStateは、コンポーネント内で状態(state)を管理するための最も基本的なHookです。
基本構文
React (TypeScript)
import { useState } from 'react';
function Counter() {
// [現在の値, 更新関数] = useState(初期値)
const [count, setCount] = useState(0);
return (
<div>
<p>カウント: {count}</p>
<button onClick={() => setCount(count + 1)}>
増やす
</button>
</div>
);
}
例1: テキスト入力フォーム
React
function NameForm() {
const [name, setName] = useState('');
const handleChange = (e) => {
setName(e.target.value);
};
return (
<div>
<input
type="text"
value={name}
onChange={handleChange}
placeholder="名前を入力"
/>
<p>こんにちは、{name || 'ゲスト'}さん!</p>
</div>
);
}
例2: オブジェクトの状態管理
React
function UserProfile() {
const [user, setUser] = useState({
name: '',
email: '',
age: 0
});
// オブジェクトの一部だけ更新する場合はスプレッド構文を使う
const updateName = (newName) => {
setUser({ ...user, name: newName });
};
return (
<input
value={user.name}
onChange={(e) => updateName(e.target.value)}
/>
);
}
注意:オブジェクトや配列の状態を更新する場合は、必ず新しいオブジェクト/配列を作成してください。直接変更しても再レンダリングされません。
例3: 配列の状態管理
React
function TodoList() {
const [todos, setTodos] = useState([]);
const [input, setInput] = useState('');
// 追加
const addTodo = () => {
if (input.trim()) {
setTodos([...todos, { id: Date.now(), text: input }]);
setInput('');
}
};
// 削除
const removeTodo = (id) => {
setTodos(todos.filter(todo => todo.id !== id));
};
return (
<div>
<input value={input} onChange={(e) => setInput(e.target.value)} />
<button onClick={addTodo}>追加</button>
<ul>
{todos.map(todo => (
<li key={todo.id}>
{todo.text}
<button onClick={() => removeTodo(todo.id)}>削除</button>
</li>
))}
</ul>
</div>
);
}
useEffect - 副作用の処理
useEffectは、コンポーネントのレンダリング後に実行される処理(副作用)を定義するHookです。
基本構文
React
import { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
// 依存配列なし:毎回のレンダリング後に実行
useEffect(() => {
console.log('レンダリングされました');
});
// 空の依存配列:マウント時のみ実行
useEffect(() => {
console.log('コンポーネントがマウントされました');
}, []);
// 依存配列あり:countが変化した時に実行
useEffect(() => {
console.log('countが変更されました:', count);
}, [count]);
return <p>{count}</p>;
}
依存配列なし
毎回のレンダリング後に実行
空の配列 []
マウント時に1回だけ実行
[value]
valueが変化した時に実行
return関数
クリーンアップ処理
例1: APIからデータを取得
React
function UserList() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchUsers = async () => {
try {
const response = await fetch('https://api.example.com/users');
const data = await response.json();
setUsers(data);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
fetchUsers();
}, []); // 空の配列:マウント時に1回だけ実行
if (loading) return <p>読み込み中...</p>;
if (error) return <p>エラー: {error}</p>;
return (
<ul>
{users.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
);
}
例2: クリーンアップ処理(タイマー)
React
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
// タイマーを開始
const intervalId = setInterval(() => {
setSeconds(prev => prev + 1);
}, 1000);
// クリーンアップ:コンポーネントがアンマウントされる時にタイマーを解除
return () => {
clearInterval(intervalId);
};
}, []); // マウント時に1回だけ実行
return <p>経過時間: {seconds}秒</p>;
}
クリーンアップが必要なケース:
- setInterval / setTimeout のクリア
- イベントリスナーの解除
- WebSocket接続の切断
- 外部ライブラリのインスタンス破棄
Hooksのルール
Hooksには守るべき2つの重要なルールがあります。
ルール1: トップレベルでのみ呼び出す
条件分岐やループの中でHooksを呼び出さないでください。
悪い例 ❌
function BadExample({ isLoggedIn }) {
// ❌ 条件分岐の中でHooksを呼んではいけない
if (isLoggedIn) {
const [user, setUser] = useState(null);
}
}
良い例 ✅
function GoodExample({ isLoggedIn }) {
// ✅ 常にトップレベルで呼び出す
const [user, setUser] = useState(null);
// 条件分岐はHooksの後で行う
if (!isLoggedIn) {
return <p>ログインしてください</p>;
}
}
ルール2: React関数内でのみ呼び出す
Hooksは関数コンポーネントかカスタムHooksの中でのみ使用できます。
実践的なパターン
パターン1: フォーム入力のバリデーション
React
function LoginForm() {
const [email, setEmail] = useState('');
const [error, setError] = useState('');
// emailが変更されるたびにバリデーション
useEffect(() => {
if (email && !email.includes('@')) {
setError('有効なメールアドレスを入力してください');
} else {
setError('');
}
}, [email]);
return (
<div>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
{error && <p style={{ color: 'red' }}>{error}</p>}
</div>
);
}
その他の便利なHooks
useContext
グローバルな状態を共有
useReducer
複雑な状態管理に
useRef
DOM参照や値の保持
useMemo
計算結果のメモ化
まとめ
useStateとuseEffectはReact開発の基盤となるHooksです。この2つをしっかり理解すれば、ほとんどのReactアプリケーションを構築できます。
次のステップ:基本をマスターしたら、useContextでグローバル状態管理、useReducerで複雑な状態管理、カスタムHooksの作成に進みましょう。
H
honualohak編集部
テクノロジーで人々の日常をより便利に。AI、プログラミング、Web開発に関する情報を発信しています。