Skip to Content

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>
  )
}
javascript

スプレッド構文 { ...user } とは?
{ ...user, name: '新しい値' } は「userの全プロパティをコピーして、nameだけ上書き」という意味です。
user.name = '新しい値' と直接書き換えると、Reactが変更を検知できないので必ずこの方法を使います。


useEffect — 副作用を扱う

useEffect はコンポーネントの「副作用」を管理するフックです。

副作用とは

  • API からデータを取得する
  • タイマーをセットする
  • ブラウザのタイトルを変更する

など、「Reactの外側の世界」に触れる処理のことです。

基本的な書き方

useEffect(() => {
  // 実行したい処理
}, [依存配列])
javascript

依存配列 の中に入れた値が変わるたびに、中の処理が実行されます。

依存配列タイミング
なし毎回のレンダリング後
[](空配列)初回レンダリング後のみ
[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>
  )
}
javascript

ボタンを押すたびにブラウザのタブのタイトルが変わるのを確認しましょう。


ステップ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>
  )
}
javascript

jsonplaceholder.typicode.com とは?
テスト用のダミーAPIです。実際のAPIがなくても、データを取得するコードのテストができます。


ステップ3: async/await で書き直す

fetchasync/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()
}, [])
javascript

なぜ useEffect(async () => { ... }) とは書けないの?
useEffect のコールバック関数は async にできません(技術的な制約があります)。
代わりに、内部で async 関数を定義してすぐ呼び出すパターンを使います。


確認しよう

  • useEffect でブラウザのタイトルを変更できた
  • useEffect + fetch でAPIからデータを取得できた
  • loading で読み込み中の状態を表示できた
  • 依存配列の役割を説明できる

AIに聞いてみよう

「useEffectのクリーンアップ関数とは何ですか?どんなときに使いますか?」


次のステップ

App Routerでページ遷移

Last updated on