useStateとuseEffect
このページで学ぶこと
useStateの応用的な使い方がわかるuseEffectでコンポーネントのライフサイクルを扱える- 外部APIのデータをフェッチできる
useState の復習と応用
前のページで useState の基本は学びました。ここでは少し応用的な使い方を見てみましょう。
オブジェクトをstateにする
'use client'
import { useState } from 'react'
export default function ProfileForm() {
// オブジェクトをstateにする
const [user, setUser] = useState({ name: '', age: '' })
const handleChangeName = (e) => {
// ✅ スプレッド構文で既存の値を保ちつつ、変更した部分だけ更新する
setUser({ ...user, name: e.target.value })
}
const handleChangeAge = (e) => {
setUser({ ...user, age: e.target.value })
}
return (
<div>
<input value={user.name} onChange={handleChangeName} placeholder="名前" />
<input value={user.age} onChange={handleChangeAge} placeholder="年齢" />
<p>{user.name}({user.age}歳)</p>
</div>
)
}スプレッド構文
{ ...user }とは?
{ ...user, name: '新しい値' }は「userの全プロパティをコピーして、nameだけ上書き」という意味です。
user.name = '新しい値'と直接書き換えると、Reactが変更を検知できないので必ずこの方法を使います。
useEffect — 副作用を扱う
useEffect はコンポーネントの「副作用」を管理するフックです。
副作用とは
- API からデータを取得する
- タイマーをセットする
- ブラウザのタイトルを変更する
など、「Reactの外側の世界」に触れる処理のことです。
基本的な書き方
useEffect(() => {
// 実行したい処理
}, [依存配列])依存配列 の中に入れた値が変わるたびに、中の処理が実行されます。
| 依存配列 | タイミング |
|---|---|
| なし | 毎回のレンダリング後 |
[](空配列) | 初回レンダリング後のみ |
[count] | count が変わるたび |
やってみよう
ステップ1: タイトルを動的に変える
'use client'
import { useState, useEffect } from 'react'
export default function TitleChanger() {
const [count, setCount] = useState(0)
// count が変わるたびにブラウザのタイトルを更新する
useEffect(() => {
document.title = `カウント: ${count}`
}, [count]) // count が変わるたびに実行
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
)
}ボタンを押すたびにブラウザのタブのタイトルが変わるのを確認しましょう。
ステップ2: APIからデータを取得する
useEffect の最も典型的な使い方は「ページが表示されたらAPIを叩いてデータを取得する」です。
'use client'
import { useState, useEffect } from 'react'
export default function UserList() {
const [users, setUsers] = useState([])
const [loading, setLoading] = useState(true) // 読み込み中かどうか
useEffect(() => {
// ① コンポーネントが表示されたら実行
fetch('https://jsonplaceholder.typicode.com/users')
.then((res) => res.json()) // ② JSONに変換
.then((data) => {
setUsers(data) // ③ stateに保存
setLoading(false) // ④ 読み込み完了
})
}, []) // 空配列 = 初回のみ実行
if (loading) {
return <p>読み込み中...</p>
}
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
)
}
jsonplaceholder.typicode.comとは?
テスト用のダミーAPIです。実際のAPIがなくても、データを取得するコードのテストができます。
ステップ3: async/await で書き直す
fetch は async/await で書くと読みやすくなります。
useEffect(() => {
// ✅ useEffect の中で async 関数を定義してすぐ呼び出す
const fetchUsers = async () => {
const res = await fetch('https://jsonplaceholder.typicode.com/users')
const data = await res.json()
setUsers(data)
setLoading(false)
}
fetchUsers()
}, [])なぜ
useEffect(async () => { ... })とは書けないの?
useEffectのコールバック関数はasyncにできません(技術的な制約があります)。
代わりに、内部でasync関数を定義してすぐ呼び出すパターンを使います。
確認しよう
-
useEffectでブラウザのタイトルを変更できた -
useEffect+fetchでAPIからデータを取得できた -
loadingで読み込み中の状態を表示できた - 依存配列の役割を説明できる
AIに聞いてみよう
「useEffectのクリーンアップ関数とは何ですか?どんなときに使いますか?」
次のステップ
Last updated on