「ボタンをクリックしたら表示を切り替えたい…」 「入力フォームの値を保持したい…」
静的なコンポーネントは作れるようになったけれど、ユーザーの操作に応じて画面を変化させたいと思ったことはありませんか?実は、ReactのuseState
を使えば、そんな動的なUIを簡単に実装できるんです。
今回は、React Hooksの中でも最も基本的な「useState」について、実践的なコード例を交えながら解説していきます。この記事を読めば、インタラクティブなUIコンポーネントが作れるようになり、Reactの醍醐味を味わえるはずです。
Reactの状態管理:useStateの基礎を理解しよう
「ボタンをクリックしたら表示を切り替えたい…」 「入力フォームの値を保持したい…」
静的なコンポーネントは作れるようになったけれど、ユーザーの操作に応じて画面を変化させたいと思ったことはありませんか?実は、ReactのuseState
を使えば、そんな動的なUIを簡単に実装できるんです。
今回は、React Hooksの中でも最も基本的な「useState」について、実践的なコード例を交えながら解説していきます。この記事を読めば、インタラクティブなUIコンポーネントが作れるようになり、Reactの醍醐味を味わえるはずです。
useStateとは何か
useStateは、Reactコンポーネントに「状態」を追加するためのHookです。状態とは、時間とともに変化する可能性のあるデータのことです。
たとえば:
- ボタンが押されているかどうか
- フォームに入力された文字列
- 商品の数量
- モーダルが開いているかどうか
これらはすべて「状態」として管理できます。
useStateの基本的な使い方
useStateは以下のような形で使います:
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>カウント: {count}</p>
<button onClick={() => setCount(count + 1)}>
増やす
</button>
</div>
);
}
ここで重要なポイントは:
useState
をreact
からインポートuseState(初期値)
で状態を初期化- 配列の分割代入で状態変数と更新関数を取得
- 更新関数を使って状態を変更
実践的なuseState活用例
1. シンプルなトグルボタン
import React, { useState } from 'react';
const ToggleButton = () => {
const [isOn, setIsOn] = useState(false);
const toggleStyles = {
on: 'bg-blue-500 text-white',
off: 'bg-gray-300 text-gray-700'
};
return (
<div className="space-y-4">
<button
className={`px-4 py-2 rounded ${isOn ? toggleStyles.on : toggleStyles.off}`}
onClick={() => setIsOn(!isOn)}
>
{isOn ? 'ON' : 'OFF'}
</button>
<p className="text-gray-600">
現在の状態: {isOn ? 'オン' : 'オフ'}
</p>
</div>
);
};
export default ToggleButton;
2. 入力フォームの実装
import React, { useState } from 'react';
const InputForm = () => {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [message, setMessage] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
// ここで入力値を使った処理を行う
alert(`名前: ${name}\nメール: ${email}\nメッセージ: ${message}`);
};
return (
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label className="block text-sm font-medium text-gray-700">お名前</label>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
className="mt-1 block w-full rounded border-gray-300 shadow-sm"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">メールアドレス</label>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
className="mt-1 block w-full rounded border-gray-300 shadow-sm"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">メッセージ</label>
<textarea
value={message}
onChange={(e) => setMessage(e.target.value)}
className="mt-1 block w-full rounded border-gray-300 shadow-sm"
rows="4"
/>
</div>
<button
type="submit"
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
>
送信
</button>
</form>
);
};
export default InputForm;
よくある間違いと解決方法
1. 状態を直接変更しようとする
// ❌ 誤った使い方
const [count, setCount] = useState(0);
count = count + 1; // 直接代入はNG
// ✅ 正しい使い方
const [count, setCount] = useState(0);
setCount(count + 1); // 更新関数を使う
2. 前の状態に基づく更新
// ❌ 更新のタイミングによっては期待通りに動かないことも
setCount(count + 1);
// ✅ 前の状態を使って更新する場合は関数を渡す
setCount(prevCount => prevCount + 1);
3. オブジェクトの状態更新
// ❌ オブジェクトの一部だけを更新しようとする
const [user, setUser] = useState({ name: '', email: '' });
setUser({ name: 'John' }); // emailが消えてしまう
// ✅ スプレッド構文で既存の値を保持
setUser(prevUser => ({ ...prevUser, name: 'John' }));
useStateのベストプラクティス
1. 明確な命名
// ❌ 曖昧な命名
const [x, setX] = useState(false);
// ✅ 目的が明確な命名
const [isVisible, setIsVisible] = useState(false);
const [userName, setUserName] = useState('');
2. 適切な粒度での状態管理
// ❌ 1つのオブジェクトにまとめすぎ
const [form, setForm] = useState({
name: '',
email: '',
age: '',
address: ''
});
// ✅ 適切に分割
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [age, setAge] = useState('');
const [address, setAddress] = useState('');
まとめ
useStateを使うことで、動的なUIを実装できることがわかりました。重要なポイントを復習しましょう:
- useStateは状態を管理するためのHook
- 状態変数と更新関数がセットで提供される
- 状態の更新は必ず更新関数を使う
- 前の状態に基づく更新は関数を使う
- 適切な粒度で状態を分割する
次回は、useStateのより実践的な使い方について学んでいきます。
複数の状態を組み合わせた複雑なフォームの実装や、パフォーマンスを考慮した状態管理など、実務で使えるテクニックを解説していきますのでお楽しみに!