React学習記録

【React基礎】useStateとは?初心者向けに分かりやすく解説

yuya_react

はじめに

こんにちは、優也@月収100万を目指して月100時間勉強する男 です。

前回の記事「【2026年版】Viteで始めるReact開発環境の構築方法」で、React開発環境が整いました。今回は、Reactで最も重要な概念の一つであるuseStateについて解説します。

useStateはReactでデータを管理するための基本的な仕組みです。TODOアプリのようなインタラクティブなアプリを作るには、useStateの理解が必須です。

この記事では、useStateの基本から実践的な使い方まで、初心者でも理解できるように丁寧に解説していきます。

useStateとは?

useStateは、Reactコンポーネント内で「状態(state)」を管理するためのHook(フック)です。

状態(state)って何?

状態とは、アプリ内で変化するデータのことです。

具体例:

  • カウンターの数字
  • 入力フォームの文字
  • TODOリストの内容
  • ボタンのON/OFF状態

これらの「変化するデータ」をReactで管理するのがuseStateの役割です。

なぜuseStateが必要?

普通の変数では、値を変更しても画面は更新されません

// ❌ これでは画面が更新されない
let count = 0;

function handleClick() {
  count = count + 1;  <em>// 値は変わるが画面は変わらない</em>
  console.log(count); <em>// コンソールには表示される</em>
}

Reactでは、stateが変更されると自動的に画面が再描画されます。これがuseStateを使う最大の理由です。

useStateの基本的な書き方

基本構文

import { useState } from 'react';

function App() {
  const [count, setCount] = useState(0);
  
  return (
    <div>
      <p>カウント: {count}</p>
    </div>
  );
}

構文の分解

const [count, setCount] = useState(0);

この1行を分解すると:

  1. count – 現在の値を保持する変数
  2. setCount – 値を更新するための関数
  3. useState(0) – 初期値を0に設定

命名規則:

  • 値: countnameisOpen など
  • 更新関数: setCountsetNamesetIsOpen など(先頭にsetを付ける)

配列の分割代入

const [count, setCount] = useState(0);

これは配列の分割代入という構文です。以下と同じ意味:

const stateArray = useState(0);
const count = stateArray[0];     // 現在の値
const setCount = stateArray[1];  // 更新関数

分割代入を使うことで、1行で両方を取得できます。

実例1: シンプルなカウンター

まずは最もシンプルな例から見ていきましょう。

コード全体

import { useState } from 'react';

function App() {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(count + 1);
  };

  const decrement = () => {
    setCount(count - 1);
  };

  const reset = () => {
    setCount(0);
  };

  return (
    <div>
      <h1>カウンター</h1>
      <p>現在の値: {count}</p>
      <button onClick={increment}>+1</button>
      <button onClick={decrement}>-1</button>
      <button onClick={reset}>リセット</button>
    </div>
  );
}

export default App;

動作の流れ

  1. 初期値は0
  2. +1ボタンをクリック
  3. increment関数が実行される
  4. setCount(count + 1)で値が更新される
  5. Reactが自動的に画面を再描画
  6. 新しい値が表示される

ポイント

  • countを直接変更してはいけない(count = count + 1NG)
  • 必ずsetCountを使って更新する
  • 更新すると自動的に画面が再レンダリングされる

実例2: 入力フォームの管理

次は、よく使うパターンの入力フォーム管理です。

コード

import { useState } from 'react';

function App() {
  const [name, setName] = useState('');

  const handleChange = (e) => {
    setName(e.target.value);
  };

  return (
    <div>
      <h1>名前入力フォーム</h1>
      <input 
        type="text" 
        value={name} 
        onChange={handleChange} 
        placeholder="名前を入力"
      />
      <p>入力された名前: {name}</p>
    </div>
  );
}

export default App;

仕組み

  1. 初期値は空文字''
  2. ユーザーが文字を入力
  3. onChangeイベントが発火
  4. handleChangeが実行される
  5. setName(e.target.value)で入力値が更新
  6. 画面に反映される

リアルタイムで反映される

このコードの特徴は、入力と同時にstateが更新される点です。これを制御コンポーネントと呼びます。

実例3: 複数のstateを管理

1つのコンポーネントで複数のstateを持つこともできます。

コード

import { useState } from 'react';

function App() {
  const [name, setName] = useState('');
  const [age, setAge] = useState(0);
  const [isStudent, setIsStudent] = useState(false);

  return (
    <div>
      <h1>プロフィール入力</h1>
      
      <div>
        <label>名前:</label>
        <input 
          type="text" 
          value={name} 
          onChange={(e) => setName(e.target.value)} 
        />
      </div>

      <div>
        <label>年齢:</label>
        <input 
          type="number" 
          value={age} 
          onChange={(e) => setAge(Number(e.target.value))} 
        />
      </div>

      <div>
        <label>
          <input 
            type="checkbox" 
            checked={isStudent} 
            onChange={(e) => setIsStudent(e.target.checked)} 
          />
          学生ですか?
        </label>
      </div>

      <div>
        <h2>入力内容</h2>
        <p>名前: {name}</p>
        <p>年齢: {age}</p>
        <p>学生: {isStudent ? 'はい' : 'いいえ'}</p>
      </div>
    </div>
  );
}

export default App;

ポイント

  • 複数のuseStateを並べて書ける
  • それぞれ独立して管理される
  • データ型は自由(文字列、数値、真偽値など)

stateの初期値について

useStateの引数には、様々な型を指定できます。

文字列

const [name, setName] = useState('太郎');
const [message, setMessage] = useState('');  <em>// 空文字</em>

数値

const [count, setCount] = useState(0);
const [price, setPrice] = useState(1000);

真偽値

const [isOpen, setIsOpen] = useState(false);
const [isLoading, setIsLoading] = useState(true);

配列

const [items, setItems] = useState([]);
const [tasks, setTasks] = useState(['task1', 'task2']);

オブジェクト

const [user, setUser] = useState({ name: '', age: 0 });
const [form, setForm] = useState({
  email: '',
  password: ''
});

よくある間違いと注意点

❌ 間違い1: stateを直接変更する

// ❌ これはダメ!
count = count + 1;
name = '新しい名前';

理由: Reactが変更を検知できず、画面が更新されません。

正解:

// ✅ 必ず更新関数を使う
setCount(count + 1);
setName('新しい名前');

❌ 間違い2: 配列やオブジェクトを直接変更

// ❌ これもダメ!
items.push('新しい要素');
user.name = '新しい名前';

理由: 参照型のデータは、中身が変わっても参照自体は同じなので、Reactが変更を検知できません。

正解:

<em>// ✅ 新しい配列/オブジェクトを作る</em>
setItems([...items, '新しい要素']);
setUser({ ...user, name: '新しい名前' });

❌ 間違い3: stateの更新は非同期

setCount(count + 1);
console.log(count);  <em>// まだ古い値が表示される!</em>

理由: stateの更新は非同期で行われるため、setCountの直後ではまだ更新されていません。

対処法: 更新後の値を使いたい場合は、次のレンダリング時に参照します。

useStateを使う上でのベストプラクティス

1. stateは最小限にする

不必要にstateを増やさず、本当に必要なデータだけをstateにします。

// ❌ 計算できる値はstateにしない
const [count, setCount] = useState(0);
const [doubleCount, setDoubleCount] = useState(0);  // 不要!

<em>// ✅ 計算で求められる値は変数にする</em>
const [count, setCount] = useState(0);
const doubleCount = count * 2;  // これでOK

2. 関連するstateはまとめる

<em>// ❌ バラバラに管理</em>
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [age, setAge] = useState(0);

<em>// ✅ オブジェクトにまとめる</em>
const [user, setUser] = useState({
  firstName: '',
  lastName: '',
  age: 0
});

3. 命名は分かりやすく

<em>// ❌ 分かりにくい</em>
const [x, setX] = useState(0);
const [flg, setFlg] = useState(false);

<em>// ✅ 分かりやすい</em>
const [count, setCount] = useState(0);
const [isVisible, setIsVisible] = useState(false);

TODOアプリでの使用例

実際のTODOアプリでは、このようにuseStateを使います:

import { useState } from 'react';

function App() {
  const [inputTask, setInputTask] = useState('');
  const [tasks, setTasks] = useState([]);

  const addTask = () => {
    setTasks([...tasks, inputTask]);
    setInputTask('');  // 入力欄をクリア
  };

  return (
    <div>
      <h1>TODOアプリ</h1>
      <input 
        value={inputTask} 
        onChange={(e) => setInputTask(e.target.value)} 
      />
      <button onClick={addTask}>追加</button>
      
      <ul>
        {tasks.map((task, index) => (
          <li key={index}>{task}</li>
        ))}
      </ul>
    </div>
  );
}

export default App;

このコードでは:

  • inputTask: 入力中のテキストを管理
  • tasks: タスクの配列を管理

2つのstateを使い分けています。

まとめ

useStateはReactの最も基本的で重要なHookです。

重要ポイント:

  • ✅ useStateで状態を管理すると、値の変更で自動的に画面が更新される
  • ✅ 構文: const [値, 更新関数] = useState(初期値)
  • ✅ 値を変更する時は必ず更新関数を使う
  • ✅ 配列やオブジェクトは新しいものを作って更新
  • ✅ stateの更新は非同期

使えるデータ型:

  • 文字列、数値、真偽値
  • 配列、オブジェクト

useStateを理解することで、ユーザーの操作に反応するインタラクティブなアプリが作れるようになります。次回は、イベントハンドラについて詳しく解説します!


この記事のシリーズ:

  1. 【React入門】未経験からReactを学んで最初のTODOアプリを作った話
  2. 【2025年版】Viteで始めるReact開発環境の構築方法
  3. 【React基礎】useStateとは?初心者向けに分かりやすく解説 ← 今ここ
  4. 【React】イベントハンドラの書き方完全ガイド(次回)

練習問題

理解を深めるために、以下を自分で実装してみましょう:

  1. ON/OFFトグルボタン: ボタンを押すたびに「ON」「OFF」が切り替わる
  2. テキストカウンター: 入力した文字数をリアルタイムで表示
  3. 好きな色選択: ボタンで背景色を変更できるアプリ

次回の記事で詳しく解説するので、ぜひ挑戦してみてください!

あとがき

月100時間の学習時間の中で、今月はReactに集中して取り組んでいます。Instagramでは、Instagramでは、フリーランスとして月収100万円を目指す道のりを、リアルタイムで発信していきますので、ぜひフォローしてください!

ABOUT ME
記事URLをコピーしました