React - 第2章:useState

React - useState

useStateで状態管理を学ぼう

useState - 状態管理の基礎

Reactで、「変化する値」を扱うには、useStateを使います。


状態(State)とは?

状態とは、「時間とともに変化する値」のことです。

例:

  • カウンター(クリックするたびに増える数値)
  • 入力フォームの値
  • モーダルの開閉状態
  • チェックボックスのON/OFF

なぜuseStateが必要?

通常の変数では、Reactは再レンダリングしてくれません。

❌ 通常の変数(動かない)

function Counter() {
  let count = 0;  // 通常の変数
  
  const increment = () => {
    count = count + 1;
    console.log(count);  // コンソールには表示されるが...
  };
  
  return (
    <div>
      <p>カウント: {count}</p>  {/* 画面は更新されない! */}
      <button onClick={increment}>増やす</button>
    </div>
  );
}

✅ useState(動く!)

import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);  // useState を使う
  
  const increment = () => {
    setCount(count + 1);  // setCount で更新
  };
  
  return (
    <div>
      <p>カウント: {count}</p>  {/* 画面が更新される! */}
      <button onClick={increment}>増やす</button>
    </div>
  );
}

useStateの基本

書き方

const [状態変数, 更新関数] = useState(初期値);
  • 状態変数: 現在の値を格納
  • 更新関数: 値を更新するための関数
  • 初期値: 最初の値

具体例

import { useState } from 'react';

function Example() {
  // countという状態を作る、初期値は0
  const [count, setCount] = useState(0);
  
  return (
    <div>
      <p>現在の値: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        増やす
      </button>
    </div>
  );
}

useStateの戻り値はタプル型

useStateの戻り値は、タプル型です。

// useStateの戻り値
const result = useState(0);
// result の型: [number, (value: number) => void]

// 分割代入で取り出す
const [count, setCount] = result;
// count: number
// setCount: (value: number) => void

タプル型とは?

タプル型は、要素数と各要素の型が決まっている配列です。

  • 1番目の要素: 現在の状態値
  • 2番目の要素: 状態を更新する関数
// useStateは必ず2つの要素を返す
const [count, setCount] = useState(0);
//     ↑       ↑
//   状態値  更新関数

// 複数のuseStateでも同じ
const [name, setName] = useState("");
const [isOpen, setIsOpen] = useState(false);

なぜタプル型を使うのか?

タプル型のおかげで、好きな名前をつけられます。

// もしオブジェクトだったら...
const { value, setValue } = useState(0);  // 名前が固定される

// タプルだから...
const [count, setCount] = useState(0);       // 好きな名前!
const [score, setScore] = useState(0);       // これも!
const [total, setTotal] = useState(0);       // 何度でも使える!

💡 タプル型について詳しく学ぶ: 第2章「TypeScript基礎 - タプル型」でタプル型の基礎を学べます。


いろいろな型の状態

数値の状態

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

文字列の状態

function NameInput() {
  const [name, setName] = useState("");
  
  return (
    <div>
      <input 
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)}
        placeholder="名前を入力"
      />
      <p>こんにちは、{name}さん!</p>
    </div>
  );
}

真偽値の状態

function ToggleButton() {
  const [isOn, setIsOn] = useState(false);
  
  return (
    <div>
      <p>状態: {isOn ? "ON" : "OFF"}</p>
      <button onClick={() => setIsOn(!isOn)}>
        切り替え
      </button>
    </div>
  );
}

複数のuseStateを使う

1つのコンポーネントで、複数の状態を管理できます。

function LoginForm() {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [rememberMe, setRememberMe] = useState(false);
  
  const handleSubmit = () => {
    console.log({ email, password, rememberMe });
  };
  
  return (
    <div>
      <input 
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="メールアドレス"
      />
      <input 
        type="password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
        placeholder="パスワード"
      />
      <label>
        <input 
          type="checkbox"
          checked={rememberMe}
          onChange={(e) => setRememberMe(e.target.checked)}
        />
        ログイン状態を保持
      </label>
      <button onClick={handleSubmit}>ログイン</button>
    </div>
  );
}

ポイント:

  • それぞれの状態に別々のuseStateを使う
  • 関連する値でも、基本的には別々の状態にする
  • 必要なだけuseStateを使ってOK

よくある間違い

❌ 直接値を代入しない

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

// ❌ ダメな例
count = 5;  // 直接代入してはダメ!

// ✅ 正しい例
setCount(5);  // 更新関数を使う

❌ 条件によって異なる数のuseStateを呼ばない

// ❌ ダメな例
function Example() {
  const [count, setCount] = useState(0);
  
  if (count > 10) {
    const [message, setMessage] = useState("");  // 条件内でuseState
  }
  
  return <div>...</div>;
}

// ✅ 正しい例
function Example() {
  const [count, setCount] = useState(0);
  const [message, setMessage] = useState("");  // 常に同じ順番で
  
  return <div>...</div>;
}

理由: Reactは、useStateを呼ばれた順番で状態を管理しています。条件によって順番が変わると、正しく動作しません。


実践例:シンプルなカウンターアプリ

import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);
  
  return (
    <div style={{ textAlign: 'center', padding: '20px' }}>
      <h1>カウンター</h1>
      <p style={{ fontSize: '48px', fontWeight: 'bold' }}>
        {count}
      </p>
      <div style={{ display: 'flex', gap: '10px', justifyContent: 'center' }}>
        <button onClick={() => setCount(count - 1)}>-1</button>
        <button onClick={() => setCount(0)}>リセット</button>
        <button onClick={() => setCount(count + 1)}>+1</button>
      </div>
    </div>
  );
}

export default Counter;

もっと学びたい人へ

useStateには、この章で紹介した以外にも、いくつかの使い方があります。

💡 Tips

より高度な使い方については、Tipsセクションで学べます:


まとめ

useStateの基本

  • useState: 状態(変化する値)を管理するHook
  • 書き方: const [状態, 更新関数] = useState(初期値)
  • 更新方法: 更新関数を使う(直接代入しない)

状態の型

  • 数値: カウンターなど
  • 文字列: 入力フォームの値など
  • 真偽値: ON/OFF、開閉状態など

ルール

  • 複数のuseStateを使える
  • useStateは常に同じ順番で呼ぶ
  • 状態は直接変更せず、更新関数を使う

次は、副作用を扱うuseEffectを学びましょう!