React

React useStateの使い方|コンポーネントの状態管理入門

React Hooks useState

React useStateの使い方
コンポーネントの状態管理入門

useStateはReactで最も基本的なHookで、コンポーネントに「状態(state)」を持たせることができます。
この記事では、useStateの基本から実践的なパターンまで解説します。

こんな人向けの記事です

  • React Hooksの基本を学びたい
  • useStateの使い方を知りたい
  • フォームやカウンターなどの状態管理を実装したい

Step 1useStateの基本

React(JSX)
import { useState } from 'react';

function Counter() {
  // [現在の値, 更新関数] = useState(初期値)
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>カウント: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        +1
      </button>
    </div>
  );
}
要素役割
count現在の状態の値(読み取り専用)
setCount状態を更新する関数
useState(0)初期値を0に設定
状態が変わるとコンポーネントが再レンダリングされる
setCount() を呼ぶと、Reactがコンポーネントを再レンダリングし、画面が更新されます。
通常の変数(let count = 0)では画面が更新されません。

Step 2数値の状態管理

React(JSX)
function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>{count}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
      <button onClick={() => setCount(count - 1)}>-1</button>
      <button onClick={() => setCount(0)}>リセット</button>
    </div>
  );
}
前の値を元に更新する場合は関数形式を使う
連続して更新する場合、setCount(count + 1) だと古い値を参照する可能性があります。
setCount(prev => prev + 1) のように関数形式を使うと安全です。

Step 3文字列の状態管理(フォーム)

React(JSX)
function SearchForm() {
  const [query, setQuery] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log('検索:', query);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        placeholder="検索ワードを入力"
      />
      <button type="submit">検索</button>
    </form>
  );
}

Step 4配列の状態管理

React(JSX)
function TodoList() {
  const [todos, setTodos] = useState([]);
  const [input, setInput] = useState('');

  // 追加
  const addTodo = () => {
    setTodos([...todos, input]);  // スプレッド構文で新しい配列を作る
    setInput('');
  };

  // 削除
  const removeTodo = (index) => {
    setTodos(todos.filter((_, i) => i !== index));
  };

  return (
    <div>
      <input value={input} onChange={(e) => setInput(e.target.value)} />
      <button onClick={addTodo}>追加</button>
      <ul>
        {todos.map((todo, i) => (
          <li key={i}>
            {todo}
            <button onClick={() => removeTodo(i)}>削除</button>
          </li>
        ))}
      </ul>
    </div>
  );
}
配列やオブジェクトは直接変更しない
todos.push(item) のように直接変更してはいけません。
必ず新しい配列/オブジェクトを作って setTodos() に渡してください。

Step 5オブジェクトの状態管理

React(JSX)
function UserForm() {
  const [user, setUser] = useState({
    name: '',
    email: '',
    age: 0,
  });

  const handleChange = (e) => {
    setUser({
      ...user,                      // 既存のプロパティをコピー
      [e.target.name]: e.target.value,  // 変更された項目だけ上書き
    });
  };

  return (
    <form>
      <input name="name" value={user.name} onChange={handleChange} />
      <input name="email" value={user.email} onChange={handleChange} />
      <input name="age" type="number" value={user.age} onChange={handleChange} />
    </form>
  );
}

Step 6useStateの注意点

ルール説明
トップレベルでのみ呼ぶif文やfor文の中でuseStateを呼ばない
関数コンポーネント内で呼ぶ通常の関数では使えない
stateを直接変更しない必ずset関数を使う
更新は非同期setCountの直後にcountを参照しても古い値のまま

まとめ

  • const [値, set関数] = useState(初期値) で状態を定義
  • set関数を呼ぶとコンポーネントが再レンダリングされる
  • 前の値を元にする場合は関数形式 setPrev(prev => ...)
  • 配列・オブジェクトは直接変更せず、新しいものを作って渡す
  • useStateはコンポーネントのトップレベルでのみ呼ぶ