モダンJavaScriptの基礎から始める挫折しないためのReact入門 60日コース | Reactの基本 - DAY 19:State更新

React 60日で身につけるReact
スポンサーリンク
スポンサーリンク
  1. DAY 19:State更新 前半 ― 「いろいろな値を安全に更新する」感覚を身につける
  2. 数値State ― カウンターで「足し算・引き算」を練習する
    1. 基本の数値State更新:count + 1
  3. 文字列State ― 入力フォームで「文字列の更新」を体感する
    1. 入力値を文字列Stateとして扱う
  4. Boolean State ― ON/OFF・表示/非表示を切り替える
    1. トグルスイッチでBoolean Stateを更新する
  5. 前のStateを利用する ― 「安全な更新」のための関数型更新
    1. 「前のStateを使う」もう一つの書き方
    2. カウンターを関数型更新で書き直す
  6. State更新関数 ― 「新しい値をReactに渡す窓口」
    1. 更新関数は「新しいStateを渡すための関数」
    2. 1. 新しい値を直接渡すパターン
    3. 2. 前のStateをもとに新しい値を計算するパターン(関数型更新)
  7. 数値・文字列・Booleanをまとめて扱うミニ例
  8. DAY 19:State更新 前半のまとめ
  9. DAY 19:State更新 中盤 ― 「実際のUIでState更新パターンを使い分ける」
  10. 数値State ― 「制限付きカウンター」で前のStateを意識する
    1. 上限・下限付きカウンターを作る
  11. 文字列State ― 「入力+リセット+追記」で更新パターンを増やす
    1. 入力値をそのままStateにする基本パターン
    2. 追記・リセットを組み合わせた例
  12. Boolean State ― 「複数の表示を切り替える」実用的なトグル
    1. 詳細表示のON/OFFを切り替える
  13. 前のStateを利用する ― 「連続更新」や「条件付き更新」で必須になる
    1. 「連続で増やす」ボタンを例にする
  14. State更新関数 ― 「直接値を渡す」と「前のStateから計算する」の使い分け
    1. 2つのパターンを意識して選ぶ
  15. 数値・文字列・Booleanを組み合わせたミニUI
  16. DAY 19:State更新 中盤のまとめ
  17. DAY 19:State更新 後半 ― 「安全で読みやすいState更新」を習慣にする
  18. 数値State ― 「計算ロジックは更新関数の中に閉じ込める」
    1. 計算をコンポーネントの外に逃がさない
  19. 文字列State ― 「入力・追記・リセットをパターンとして整理する」
    1. 入力は「新しい値をそのまま渡す」パターン
  20. Boolean State ― 「ON/OFFの意味を名前で表現する」
    1. 名前で「何がON/OFFなのか」を伝える
  21. 前のStateを利用する ― 「ロジックをState更新関数の中に閉じ込める」
    1. 条件付き更新をすべて「prev」を起点に書く
  22. State更新関数 ― 「直接値を渡す」と「関数型更新」の使い分けを定着させる
    1. 2パターンを明確に意識する
  23. まとめ用ミニテンプレート ― 「State更新の基本形」を手元に置いておく
  24. DAY 19:State更新 後半のまとめ
  25. DAY 19:State更新 制作編 ― カウンターアプリを完成させる
  26. カウンターアプリのゴールイメージを決める
  27. 数値State ― カウンターの「現在の値」を持つ
    1. countとsetCountを定義する
  28. State更新関数 ― +1 / -1 / リセットの動きを定義する
    1. +1ボタンの動き:前のStateを利用して1増やす
    2. -1ボタンの動き:前のStateを利用して1減らす
    3. リセットボタンの動き:直接値を渡して0に戻す
  29. 文字列State ― カウンターにメッセージを添える
    1. 状態に応じてメッセージを変える
  30. Boolean State ― カウンターの「拡張機能」をON/OFFする
    1. 例えば「詳細表示ON/OFF」を追加する
  31. カウンターアプリ完成版テンプレート
  32. DAY 19:カウンターアプリ制作のまとめ

DAY 19:State更新 前半 ― 「いろいろな値を安全に更新する」感覚を身につける

DAY 19では、前日までに学んだ useState を一歩進めて、Stateの更新パターンを整理していきます。 Reactでは「値をどう持つか」だけでなく、「どう安全に更新するか」がとても重要になります。

この前半では、次のポイントを扱います。

  • 数値State
  • 文字列State
  • Boolean State
  • 前のStateを利用する
  • State更新関数

それぞれをステップバイステップで確認しながら、 「State更新はこう書くと安全で読みやすい」という感覚を身につけていきます。

数値State ― カウンターで「足し算・引き算」を練習する

基本の数値State更新:count + 1

まずは、いちばんシンプルな数値Stateから見ていきます。

import { useState } from "react";

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

export default Counter;
JSX

ここで起きていることを整理すると、

  1. count は数値のStateです。
  2. setCount(count + 1) で「今の値+1」に更新しています。
  3. setCount(count - 1) で「今の値−1」に更新しています。

重要ポイント:

  • 数値Stateは、「今の値をもとに新しい値を計算する」パターンが基本です。
  • setCount(count + 1) のように、「今の count を使って新しい値を作る」書き方に慣れてください。

文字列State ― 入力フォームで「文字列の更新」を体感する

入力値を文字列Stateとして扱う

次に、文字列Stateの更新を見ていきます。

import { useState } from "react";

function NameInput() {
  const [name, setName] = useState("");

  return (
    <div>
      <input
        value={name}
        onChange={(event) => setName(event.target.value)}
        placeholder="名前を入力してください"
      />
      <p>現在の入力:{name}</p>
    </div>
  );
}

export default NameInput;
JSX

ここで起きていることをステップで整理すると、

  1. name は文字列のStateです。
  2. setName(event.target.value) で「入力欄に今入っている文字列」に更新しています。
  3. value={name} によって、入力欄の表示は常にStateと同期しています。

重要ポイント:

  • 文字列Stateは、「ユーザーの入力をそのままStateに反映する」パターンが基本です。
  • setName(...) の引数には、「新しい文字列」をそのまま渡します。

Boolean State ― ON/OFF・表示/非表示を切り替える

トグルスイッチでBoolean Stateを更新する

Boolean(真偽値)のStateは、ON/OFFや表示/非表示の切り替えに使われます。

import { useState } from "react";

function Toggle() {
  const [isOn, setIsOn] = useState(false);

  return (
    <div>
      <p>現在の状態:{isOn ? "ON" : "OFF"}</p>
      <button onClick={() => setIsOn(!isOn)}>
        切り替え
      </button>
    </div>
  );
}

export default Toggle;
JSX

ここで起きていることをステップで整理すると、

  1. isOn はBooleanのStateです(true または false)。
  2. setIsOn(!isOn) で「今の値を反転」しています。
    • truefalse
    • falsetrue
  3. 表示は isOn ? "ON" : "OFF" で切り替えています。

重要ポイント:

  • Boolean Stateは、「今の値を反転する」更新がよく使われます。
  • setIsOn(!isOn) のように、「今のStateをもとに新しいStateを作る」書き方が基本です。

前のStateを利用する ― 「安全な更新」のための関数型更新

「前のStateを使う」もう一つの書き方

ここからが少し重要な話です。 Reactでは、State更新が「まとめて処理される」ことがあり、 そのときに 「前のStateを使う更新」 を安全に書くためのパターンがあります。

それが、関数型更新と呼ばれる書き方です。

setCount((prevCount) => prevCount + 1);
JSX

これは、

  • prevCount → 「前のStateの値」
  • prevCount + 1 → 新しい値

という意味になります。

カウンターを関数型更新で書き直す

先ほどのカウンターを、関数型更新で書き直してみます。

import { useState } from "react";

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

  const handleIncrement = () => {
    setCount((prevCount) => prevCount + 1);
  };

  const handleDecrement = () => {
    setCount((prevCount) => prevCount - 1);
  };

  return (
    <div>
      <p>現在のカウント:{count}</p>
      <button onClick={handleIncrement}>
        1増やす
      </button>
      <button onClick={handleDecrement}>
        1減らす
      </button>
    </div>
  );
}

export default Counter;
JSX

ここで起きていることをステップで整理すると、

  1. setCount((prevCount) => prevCount + 1);
    • Reactが「前の count の値」を prevCount として渡してくれます。
    • その prevCount をもとに新しい値を計算します。
  2. setCount((prevCount) => prevCount - 1);
    • 同じく、「前の値−1」を新しいStateとして渡します。

重要ポイント:

  • 「前のStateをもとに新しいStateを計算する」場合は、関数型更新が安全です。
  • 特に、同じStateを連続で更新するようなケースでは、この書き方が推奨されます。

State更新関数 ― 「新しい値をReactに渡す窓口」

更新関数は「新しいStateを渡すための関数」

setCountsetNamesetIsOn などの更新関数は、

「新しいStateはこれです」とReactに渡すための窓口

です。

更新関数の使い方には、主に2パターンあります。

1. 新しい値を直接渡すパターン

setName("ゲスト");
setIsOn(true);
setCount(10);
JSX
  • 「前のStateは関係なく、これを新しい値にしたい」というときに使います。

2. 前のStateをもとに新しい値を計算するパターン(関数型更新)

setCount((prevCount) => prevCount + 1);
setIsOn((prevIsOn) => !prevIsOn);
JSX
  • 「前のStateをもとに新しい値を決めたい」というときに使います。

重要ポイント:

  • 更新関数は、「新しいStateをReactに渡すための唯一の入口」です。
  • 直接代入(count = count + 1 など)は絶対に使わず、必ず更新関数を通します。

数値・文字列・Booleanをまとめて扱うミニ例

最後に、数値・文字列・BooleanのState更新を1つのコンポーネントにまとめてみます。

import { useState } from "react";

function StateDemo() {
  const [count, setCount] = useState(0);        // 数値State
  const [name, setName] = useState("");        // 文字列State
  const [isOn, setIsOn] = useState(false);     // Boolean State

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

  const toggle = () => {
    setIsOn((prevIsOn) => !prevIsOn);
  };

  const resetName = () => {
    setName("ゲスト");
  };

  return (
    <div>
      <h2>State更新デモ</h2>

      <section>
        <h3>数値State(count)</h3>
        <p>現在のカウント:{count}</p>
        <button onClick={increment}>1増やす</button>
      </section>

      <section>
        <h3>文字列State(name)</h3>
        <input
          value={name}
          onChange={(event) => setName(event.target.value)}
          placeholder="名前"
        />
        <p>現在の名前:{name}</p>
        <button onClick={resetName}>ゲストにリセット</button>
      </section>

      <section>
        <h3>Boolean State(isOn)</h3>
        <p>現在の状態:{isOn ? "ON" : "OFF"}</p>
        <button onClick={toggle}>切り替え</button>
      </section>
    </div>
  );
}

export default StateDemo;
JSX

このコンポーネントには、

  • 数値Stateの更新(setCount((prevCount) => prevCount + 1)
  • 文字列Stateの更新(入力+リセット)
  • Boolean Stateの更新(setIsOn((prevIsOn) => !prevIsOn)

がすべて含まれています。

DAY 19:State更新 前半のまとめ

この前半では、

  • 数値Stateでは「今の値をもとに新しい値を計算する」更新が基本であること
  • 文字列Stateでは「入力値をそのままStateに反映する」パターンがよく使われること
  • Boolean Stateでは「今の値を反転する」更新が典型的であること
  • 「前のStateを利用する」場合には、関数型更新(setCount((prev) => prev + 1))が安全であること
  • 更新関数は「新しいStateをReactに渡す窓口」であり、直接代入ではなく必ず更新関数を使うこと

をステップバイステップで確認しました。

中盤以降では、 この「安全なState更新」の考え方を、配列やオブジェクトなど、もう少し複雑なデータ構造にも広げていきます。


DAY 19:State更新 中盤 ― 「実際のUIでState更新パターンを使い分ける」

DAY 19の中盤では、前半で触れた

  • 数値State
  • 文字列State
  • Boolean State
  • 前のStateを利用する
  • State更新関数

を、もう少し「実際のUI」に近い形で組み合わせていきます。 単なるサンプルではなく、ミニ機能を作りながらState更新の“クセ”を体で覚えることを目標にします。

数値State ― 「制限付きカウンター」で前のStateを意識する

上限・下限付きカウンターを作る

まず、数値Stateを使って「0〜10の範囲で動くカウンター」を作ってみます。

import { useState } from "react";

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

  const increment = () => {
    setCount((prevCount) => {
      if (prevCount >= 10) {
        return prevCount; // これ以上増やさない
      }
      return prevCount + 1;
    });
  };

  const decrement = () => {
    setCount((prevCount) => {
      if (prevCount <= 0) {
        return prevCount; // これ以上減らさない
      }
      return prevCount - 1;
    });
  };

  return (
    <div>
      <p>現在のカウント:{count}</p>
      <button onClick={increment}>1増やす(最大10)</button>
      <button onClick={decrement}>1減らす(最小0)</button>
    </div>
  );
}

export default LimitedCounter;
JSX

ここで起きていることをステップで整理すると、

  1. count は数値Stateです。
  2. increment では、setCount((prevCount) => { ... }) として「前のState」を受け取っています。
  3. prevCount >= 10 のときは、そのまま prevCount を返し、上限を超えないようにしています。
  4. decrement でも同様に、prevCount <= 0 のときはそのまま返して下限を守っています。

重要ポイント:

  • 「前のStateを見て条件分岐し、新しいStateを決める」場面では、関数型更新が非常に自然です。
  • prevCount という名前を使うことで、「これは前の値だ」と読み手にも伝わりやすくなります。

文字列State ― 「入力+リセット+追記」で更新パターンを増やす

入力値をそのままStateにする基本パターン

文字列Stateの基本は、前半で見たように「入力値をそのままStateにする」パターンです。

const [text, setText] = useState("");

<input
  value={text}
  onChange={(event) => setText(event.target.value)}
/>
JSX

ここでは、event.target.value が「新しい文字列」としてそのままStateになります。

追記・リセットを組み合わせた例

ここから一歩進めて、「追記」と「リセット」を組み合わせた例を見てみます。

import { useState } from "react";

function MessageEditor() {
  const [message, setMessage] = useState("");

  const appendHello = () => {
    setMessage((prevMessage) => prevMessage + "こんにちは!");
  };

  const resetMessage = () => {
    setMessage("");
  };

  return (
    <div>
      <textarea
        value={message}
        onChange={(event) => setMessage(event.target.value)}
        placeholder="メッセージを入力してください"
      />
      <p>現在のメッセージ:</p>
      <pre>{message}</pre>

      <button onClick={appendHello}>「こんにちは!」を追記</button>
      <button onClick={resetMessage}>リセット</button>
    </div>
  );
}

export default MessageEditor;
JSX

ここで起きていることをステップで整理すると、

  1. message は文字列Stateです。
  2. 入力欄の onChange では、「新しい文字列」をそのまま setMessage に渡しています。
  3. appendHello では、setMessage((prevMessage) => prevMessage + "こんにちは!"); として「前のStateに追記」しています。
  4. resetMessage では、setMessage("") として「新しい値を直接渡す」更新をしています。

重要ポイント:

  • 文字列Stateでも、「前のStateをもとに新しい文字列を作る」関数型更新が使えます。
  • 「追記」「削除」「置き換え」などの操作をするときは、前のStateを意識すると設計しやすくなります。

Boolean State ― 「複数の表示を切り替える」実用的なトグル

詳細表示のON/OFFを切り替える

Boolean Stateは、単純なON/OFFだけでなく、「詳細表示のON/OFF」などにもよく使われます。

import { useState } from "react";

function DetailToggle() {
  const [showDetail, setShowDetail] = useState(false);

  const toggleDetail = () => {
    setShowDetail((prevShowDetail) => !prevShowDetail);
  };

  return (
    <div>
      <p>React入門 60日コース</p>
      <button onClick={toggleDetail}>
        {showDetail ? "詳細を隠す" : "詳細を表示"}
      </button>

      {showDetail && (
        <div>
          <p>DAY 1〜DAY 60まで、Reactの基礎から実践まで学びます。</p>
          <p>1日1〜2時間を目安に進めていきます。</p>
        </div>
      )}
    </div>
  );
}

export default DetailToggle;
JSX

ここで起きていることをステップで整理すると、

  1. showDetail はBoolean Stateです。
  2. toggleDetail では、setShowDetail((prevShowDetail) => !prevShowDetail); として「前の値を反転」しています。
  3. ボタンのラベルは、showDetail に応じて「詳細を隠す」「詳細を表示」を切り替えています。
  4. 詳細部分の表示は、{showDetail && (...)} で条件付きレンダリングをしています。

重要ポイント:

  • Boolean Stateは、「表示するかしないか」「開くか閉じるか」を切り替えるのに最適です。
  • setShowDetail((prev) => !prev) のように、前のStateを反転する関数型更新は非常によく使われるパターンです。

前のStateを利用する ― 「連続更新」や「条件付き更新」で必須になる

「連続で増やす」ボタンを例にする

前のStateを利用する重要性がよく分かる例として、「一度のクリックで3回増やす」ボタンを考えてみます。

import { useState } from "react";

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

  const incrementThreeTimes = () => {
    setCount((prevCount) => prevCount + 1);
    setCount((prevCount) => prevCount + 1);
    setCount((prevCount) => prevCount + 1);
  };

  return (
    <div>
      <p>現在のカウント:{count}</p>
      <button onClick={incrementThreeTimes}>
        3回増やす
      </button>
    </div>
  );
}

export default MultiIncrementCounter;
JSX

ここで起きていることをステップで整理すると、

  1. incrementThreeTimes の中で、setCount を3回呼んでいます。
  2. それぞれの setCount は、「前のState」を prevCount として受け取ります。
  3. 1回目:prevCount は現在の count(たとえば0) → 1 に更新
  4. 2回目:prevCount は「1回目の更新後の値」(1) → 2 に更新
  5. 3回目:prevCount は「2回目の更新後の値」(2) → 3 に更新

結果として、1回のクリックで count が3増えます。

重要ポイント:

  • 同じStateを連続で更新する場合、関数型更新を使うことで「前の更新結果」を正しく受け取れます。
  • setCount(count + 1); を3回書くのではなく、setCount((prev) => prev + 1); を3回書くのが安全です。

State更新関数 ― 「直接値を渡す」と「前のStateから計算する」の使い分け

2つのパターンを意識して選ぶ

State更新関数には、次の2つの使い方があります。

1. 新しい値を直接渡す

setCount(10);
setName("ゲスト");
setIsOn(true);
JSX
  • 「前のStateは関係なく、これにしたい」というときに使います。
  • リセットや固定値への変更に向いています。

2. 前のStateをもとに新しい値を計算する(関数型更新)

setCount((prevCount) => prevCount + 1);
setName((prevName) => prevName + "さん");
setIsOn((prevIsOn) => !prevIsOn);
JSX
  • 「前のStateを見てから新しい値を決めたい」というときに使います。
  • 連続更新・条件付き更新・追記などに向いています。

重要ポイント:

  • 「前のStateを使うかどうか」で、どちらのパターンを使うかを決めます。
  • 迷ったら、「前の値を見たいか?」と自分に問いかけてみると判断しやすいです。

数値・文字列・Booleanを組み合わせたミニUI

最後に、数値・文字列・BooleanのState更新を1つのミニUIにまとめてみます。

import { useState } from "react";

function MiniDashboard() {
  const [count, setCount] = useState(0);        // 数値State
  const [name, setName] = useState("ゲスト");  // 文字列State
  const [isAdmin, setIsAdmin] = useState(false); // Boolean State

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

  const changeName = () => {
    setName((prevName) => prevName + "さん");
  };

  const toggleAdmin = () => {
    setIsAdmin((prevIsAdmin) => !prevIsAdmin);
  };

  return (
    <div>
      <h2>ミニダッシュボード</h2>

      <section>
        <h3>カウント</h3>
        <p>現在のカウント:{count}</p>
        <button onClick={increment}>1増やす</button>
      </section>

      <section>
        <h3>ユーザー名</h3>
        <p>現在の名前:{name}</p>
        <button onClick={changeName}>「さん」を付ける</button>
      </section>

      <section>
        <h3>権限</h3>
        <p>権限:{isAdmin ? "管理者" : "一般ユーザー"}</p>
        <button onClick={toggleAdmin}>
          権限を切り替え
        </button>
      </section>
    </div>
  );
}

export default MiniDashboard;
JSX

このコンポーネントには、

  • 数値Stateの関数型更新(prevCount + 1
  • 文字列Stateの関数型更新(prevName + "さん"
  • Boolean Stateの関数型更新(!prevIsAdmin

がすべて含まれており、 「前のStateを利用する更新」と「State更新関数の役割」をまとめて体感できる構成になっています。

DAY 19:State更新 中盤のまとめ

この中盤では、

  • 数値Stateで「上限・下限付きカウンター」を作り、前のStateを見て条件付き更新するパターンを確認したこと
  • 文字列Stateで「入力+追記+リセット」を組み合わせ、前のStateを使った文字列操作に慣れたこと
  • Boolean Stateで「詳細表示のON/OFF」を切り替え、表示制御にStateを使う感覚をつかんだこと
  • 「連続更新」や「条件付き更新」の場面で、関数型更新(setX((prev) => ...))が必須になる理由を理解したこと
  • State更新関数には「新しい値を直接渡す」と「前のStateから計算する」の2パターンがあり、用途によって使い分けることが大事だと分かったこと
  • 数値・文字列・BooleanをまとめたミニUIを通して、State更新パターンを実際の画面構成に当てはめて考えられるようになったこと

が大きなポイントになります。

後半では、 この「前のStateを利用する」考え方を、配列やオブジェクトなど、より複雑なデータ構造に広げていき、 Reactで実務レベルのState管理に近づいていきます。


DAY 19:State更新 後半 ― 「安全で読みやすいState更新」を習慣にする

DAY 19の後半では、これまで扱ってきた

  • 数値State
  • 文字列State
  • Boolean State
  • 前のStateを利用する
  • State更新関数

をまとめて振り返りつつ、「実務でも通用する書き方」を意識して整理していきます。 ここで身につけるべきなのは、「State更新は常に“前のStateを意識して書く”」という習慣です。

数値State ― 「計算ロジックは更新関数の中に閉じ込める」

計算をコンポーネントの外に逃がさない

数値Stateを更新するとき、次のような書き方は一見シンプルですが、ロジックが散らばりやすくなります。

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

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

  // ...
}
JSX

これでも動きますが、より読みやすく安全にするなら、「前のStateを受け取って、その中で計算する」形にまとめるとよいです。

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

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

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

  return (
    <div>
      <p>現在のカウント:{count}</p>
      <button onClick={increment}>1増やす</button>
      <button onClick={decrement}>1減らす</button>
    </div>
  );
}
JSX

このように書くことで、

  • 「前のStateを使って新しいStateを計算している」ことが明確になる
  • 連続更新や非同期的な更新でも安全に動作する

というメリットがあります。

文字列State ― 「入力・追記・リセットをパターンとして整理する」

入力は「新しい値をそのまま渡す」パターン

文字列Stateの更新は、大きく3つのパターンに整理できます。

  1. 入力値をそのまま反映するjsxconst [text, setText] = useState(""); const handleChange = (event) => { setText(event.target.value); }; これは「前のStateは関係なく、新しい値をそのまま使う」パターンです。
  2. 前のStateに追記するjsxconst appendExclamation = () => { setText((prevText) => prevText + "!"); };
  3. 固定値にリセットするjsxconst resetText = () => { setText(""); };

これらを1つのコンポーネントにまとめると、更新パターンが整理されて見えてきます。

function TextPatterns() {
  const [text, setText] = useState("");

  const handleChange = (event) => {
    setText(event.target.value); // 新しい値をそのまま
  };

  const appendExclamation = () => {
    setText((prevText) => prevText + "!");
  };

  const resetText = () => {
    setText("");
  };

  return (
    <div>
      <textarea
        value={text}
        onChange={handleChange}
        placeholder="入力してください"
      />
      <p>現在のテキスト:</p>
      <pre>{text}</pre>

      <button onClick={appendExclamation}>「!」を追記</button>
      <button onClick={resetText}>リセット</button>
    </div>
  );
}
JSX

重要なのは、「前のStateを使うかどうか」で更新パターンを分けて考えることです。

Boolean State ― 「ON/OFFの意味を名前で表現する」

名前で「何がON/OFFなのか」を伝える

Boolean Stateは、名前の付け方がとても重要です。

const [isOpen, setIsOpen] = useState(false);
const [isAdmin, setIsAdmin] = useState(false);
const [showDetail, setShowDetail] = useState(false);
JSX

このように、

  • isOpen
  • isAdmin
  • showDetail

といった名前にすることで、「何がON/OFFなのか」が一目で分かります。

更新関数も、前のStateを使って反転する形が基本です。

const toggleOpen = () => {
  setIsOpen((prevIsOpen) => !prevIsOpen);
};

const toggleAdmin = () => {
  setIsAdmin((prevIsAdmin) => !prevIsAdmin);
};
JSX

Boolean Stateは、

  • 表示するかしないか
  • 権限があるかないか
  • モーダルが開いているか閉じているか

など、「二択の状態」を表すのに向いています。 その意味を名前で表現し、更新は「前のStateを反転する」形に統一すると、コードが非常に読みやすくなります。

前のStateを利用する ― 「ロジックをState更新関数の中に閉じ込める」

条件付き更新をすべて「prev」を起点に書く

前のStateを利用する場面では、「ロジックを更新関数の中に閉じ込める」意識が大切です。

たとえば、「0〜10の範囲でしか増減しないカウンター」は、次のように書けます。

const increment = () => {
  setCount((prevCount) => {
    if (prevCount >= 10) {
      return prevCount;
    }
    return prevCount + 1;
  });
};

const decrement = () => {
  setCount((prevCount) => {
    if (prevCount <= 0) {
      return prevCount;
    }
    return prevCount - 1;
  });
};
JSX

ここで、

  • 「前のStateを見て条件分岐する」
  • 「新しいStateを返す」

というロジックが、更新関数の中にきれいに閉じ込められています。

この書き方を習慣にすると、

  • どこでStateが変わるのか
  • どういう条件で変わるのか

が一目で分かるようになり、バグが減ります。

State更新関数 ― 「直接値を渡す」と「関数型更新」の使い分けを定着させる

2パターンを明確に意識する

State更新関数には、次の2つの使い方があります。

1. 新しい値を直接渡す

setCount(0);          // リセット
setName("ゲスト");    // 固定値に変更
setIsAdmin(true);     // 強制的に管理者にする
JSX

これは、

「前のStateは関係なく、この値にしたい」

というときに使います。

2. 前のStateをもとに新しい値を計算する(関数型更新)

setCount((prevCount) => prevCount + 1);
setName((prevName) => prevName + "さん");
setIsAdmin((prevIsAdmin) => !prevIsAdmin);
JSX

これは、

「前のStateを見てから、新しい値を決めたい」

というときに使います。

この2つを意識して使い分けることが、ReactのState更新を“安全で読みやすく”する鍵です。

まとめ用ミニテンプレート ― 「State更新の基本形」を手元に置いておく

最後に、数値・文字列・BooleanのState更新をまとめた「基本テンプレート」を示します。 これを自分のプロジェクトの最初のコンポーネントとして書いてみると、State更新の感覚が定着しやすくなります。

import { useState } from "react";

function StatePatterns() {
  // 数値State
  const [count, setCount] = useState(0);

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

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

  // 文字列State
  const [name, setName] = useState("ゲスト");

  const changeName = (event) => {
    setName(event.target.value);
  };

  const appendSan = () => {
    setName((prevName) => prevName + "さん");
  };

  // Boolean State
  const [isAdmin, setIsAdmin] = useState(false);

  const toggleAdmin = () => {
    setIsAdmin((prevIsAdmin) => !prevIsAdmin);
  };

  return (
    <div>
      <h2>State更新パターンまとめ</h2>

      <section>
        <h3>数値State</h3>
        <p>count:{count}</p>
        <button onClick={increment}>1増やす</button>
        <button onClick={resetCount}>0にリセット</button>
      </section>

      <section>
        <h3>文字列State</h3>
        <input
          value={name}
          onChange={changeName}
          placeholder="名前を入力"
        />
        <p>name:{name}</p>
        <button onClick={appendSan}>「さん」を付ける</button>
      </section>

      <section>
        <h3>Boolean State</h3>
        <p>権限:{isAdmin ? "管理者" : "一般ユーザー"}</p>
        <button onClick={toggleAdmin}>権限を切り替え</button>
      </section>
    </div>
  );
}

export default StatePatterns;
JSX

DAY 19:State更新 後半のまとめ

DAY 19の後半では、

  • 数値Stateの更新ロジックを「前のStateを受け取る関数の中に閉じ込める」ことで、安全性と読みやすさを高めること
  • 文字列Stateの更新を「入力」「追記」「リセット」の3パターンに整理し、前のStateを使う場面と使わない場面を区別すること
  • Boolean Stateの名前付けと反転更新(prev => !prev)を通して、「何がON/OFFなのか」をコードから伝えられるようにすること
  • 「前のStateを利用する」更新では、関数型更新を使うことで、連続更新や条件付き更新を安全に書けること
  • State更新関数には「直接値を渡す」と「前のStateから計算する」の2パターンがあり、用途に応じて使い分けること
  • 数値・文字列・Booleanをまとめたテンプレートを通して、State更新の基本形を自分の手で書けるようになること

を確認しました。

ここまで来ると、ReactのState更新は「怖いもの」ではなく、「パターンとして整理できるもの」になっているはずです。 次のステップでは、この考え方を配列やオブジェクトのStateに広げていき、より実務に近いデータ構造を扱えるようになっていきます。


DAY 19:State更新 制作編 ― カウンターアプリを完成させる

DAY 19の制作では、これまで学んできたState更新の考え方を使って、カウンターアプリを実際に作っていきます。 機能はシンプルですが、ReactのStateの基本がすべて詰まっています。

  • +1 ボタン
  • -1 ボタン
  • リセットボタン

を持つカウンターアプリを題材にして、

  • 数値State
  • 文字列State
  • Boolean State
  • 前のStateを利用する
  • State更新関数

をステップバイステップで確認していきます。

カウンターアプリのゴールイメージを決める

まず、どんなカウンターアプリを作るかをイメージします。

  • 画面中央に「現在のカウント」を表示する
  • +1 ボタンで1増える
  • -1 ボタンで1減る
  • 「リセット」ボタンで0に戻る
  • 状態に応じてメッセージを変える(例:0のときは「まだ何もカウントされていません」など)

この中に、数値State・文字列State・Boolean State・前のStateを利用する更新が自然に含まれるように設計していきます。

数値State ― カウンターの「現在の値」を持つ

countとsetCountを定義する

カウンターの中心となるのは、数値Stateです。 まずは、countsetCount を定義します。

import { useState } from "react";

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

  return (
    <div>
      <p>現在のカウント:{count}</p>
    </div>
  );
}

export default CounterApp;
JSX

ここで起きていることを整理すると、

  • count → 現在のカウントの値(数値State)
  • setCountcount を更新するための関数
  • useState(0) → 初期値は 0(最初は0からスタート)

重要ポイント:

  • カウンターアプリでは、count が「アプリの中心となるState」です。
  • 「今いくつか」を表す値は、必ずStateとして持つようにします。

State更新関数 ― +1 / -1 / リセットの動きを定義する

+1ボタンの動き:前のStateを利用して1増やす

次に、+1 ボタンの動きを定義します。 ここでは、前のStateを利用する関数型更新を使います。

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

  const handleIncrement = () => {
    setCount((prevCount) => prevCount + 1);
  };

  return (
    <div>
      <p>現在のカウント:{count}</p>
      <button onClick={handleIncrement}>+1</button>
    </div>
  );
}
JSX

ここで起きていることをステップで整理すると、

  1. handleIncrement が呼ばれると、setCount((prevCount) => prevCount + 1); が実行されます。
  2. prevCount には「前の count の値」が入ります。
  3. prevCount + 1 を新しいStateとしてReactに渡します。
  4. Reactが再レンダリングし、「新しい count」に基づいて画面を更新します。

重要ポイント:

  • setCount((prevCount) => prevCount + 1) は、数値State更新の基本形です。
  • 「前のStateをもとに新しい値を計算する」場面では、関数型更新を使うのが安全です。

-1ボタンの動き:前のStateを利用して1減らす

次に、-1 ボタンの動きを定義します。

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

  const handleIncrement = () => {
    setCount((prevCount) => prevCount + 1);
  };

  const handleDecrement = () => {
    setCount((prevCount) => prevCount - 1);
  };

  return (
    <div>
      <p>現在のカウント:{count}</p>
      <button onClick={handleIncrement}>+1</button>
      <button onClick={handleDecrement}>-1</button>
    </div>
  );
}
JSX

ここでも、

  • prevCount - 1 を新しいStateとして渡しています。
  • 「前の値を見てから1減らす」というロジックが、更新関数の中に閉じ込められています。

リセットボタンの動き:直接値を渡して0に戻す

最後に、「リセット」ボタンを追加します。 ここでは、前のStateは関係なく、固定値に戻すので、直接値を渡す更新を使います。

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

  const handleIncrement = () => {
    setCount((prevCount) => prevCount + 1);
  };

  const handleDecrement = () => {
    setCount((prevCount) => prevCount - 1);
  };

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

  return (
    <div>
      <p>現在のカウント:{count}</p>
      <button onClick={handleIncrement}>+1</button>
      <button onClick={handleDecrement}>-1</button>
      <button onClick={handleReset}>リセット</button>
    </div>
  );
}
JSX

重要ポイント:

  • 「前のStateは関係なく、特定の値にしたい」場合は、setCount(0) のように直接値を渡します。
  • 「前のStateをもとに計算したい」場合は、setCount((prev) => ...) の関数型更新を使います。
  • この使い分けが、ReactのState更新を理解するうえで非常に重要です。

文字列State ― カウンターにメッセージを添える

状態に応じてメッセージを変える

次に、文字列Stateを使って、カウンターにメッセージを添えてみます。 たとえば、

  • count === 0 のとき → 「まだ何もカウントされていません」
  • count > 0 のとき → 「カウントが進んでいます!」
  • count < 0 のとき → 「マイナス方向にカウントしています」

というメッセージを表示することを考えます。

ここでは、文字列Stateを持つ方法と、「計算結果として文字列を表示する方法」の2つがありますが、 まずは文字列Stateとして持つパターンを見てみます。

function CounterApp() {
  const [count, setCount] = useState(0);
  const [message, setMessage] = useState("まだ何もカウントされていません");

  const updateMessage = (nextCount) => {
    if (nextCount === 0) {
      setMessage("まだ何もカウントされていません");
    } else if (nextCount > 0) {
      setMessage("カウントが進んでいます!");
    } else {
      setMessage("マイナス方向にカウントしています");
    }
  };

  const handleIncrement = () => {
    setCount((prevCount) => {
      const nextCount = prevCount + 1;
      updateMessage(nextCount);
      return nextCount;
    });
  };

  const handleDecrement = () => {
    setCount((prevCount) => {
      const nextCount = prevCount - 1;
      updateMessage(nextCount);
      return nextCount;
    });
  };

  const handleReset = () => {
    setCount(0);
    updateMessage(0);
  };

  return (
    <div>
      <p>現在のカウント:{count}</p>
      <p>メッセージ:{message}</p>
      <button onClick={handleIncrement}>+1</button>
      <button onClick={handleDecrement}>-1</button>
      <button onClick={handleReset}>リセット</button>
    </div>
  );
}
JSX

ここで起きていることをステップで整理すると、

  1. message は文字列Stateで、「現在の状態に応じたメッセージ」を持っています。
  2. updateMessage(nextCount) は、「次のカウント値」に応じてメッセージを更新する関数です。
  3. handleIncrementhandleDecrement では、
    • prevCount から nextCount を計算し
    • updateMessage(nextCount) で文字列Stateを更新し
    • nextCount を数値Stateとして返しています。
  4. handleReset では、数値Stateと文字列Stateを両方リセットしています。

重要ポイント:

  • 数値Stateの更新に合わせて、文字列Stateも更新することで、「状態に応じたメッセージ」を表示できます。
  • 「次の値」を変数にしてから、数値Stateと文字列Stateの両方に反映する書き方は、実務でもよく使われるパターンです。

Boolean State ― カウンターの「拡張機能」をON/OFFする

例えば「詳細表示ON/OFF」を追加する

Boolean Stateを使って、カウンターの拡張機能をON/OFFすることもできます。 ここでは、「詳細表示」をON/OFFする例を見てみます。

function CounterApp() {
  const [count, setCount] = useState(0);
  const [showDetail, setShowDetail] = useState(false);

  const handleIncrement = () => {
    setCount((prevCount) => prevCount + 1);
  };

  const handleDecrement = () => {
    setCount((prevCount) => prevCount - 1);
  };

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

  const toggleDetail = () => {
    setShowDetail((prevShowDetail) => !prevShowDetail);
  };

  return (
    <div>
      <p>現在のカウント:{count}</p>

      <button onClick={handleIncrement}>+1</button>
      <button onClick={handleDecrement}>-1</button>
      <button onClick={handleReset}>リセット</button>

      <hr />

      <button onClick={toggleDetail}>
        {showDetail ? "詳細を隠す" : "詳細を表示"}
      </button>

      {showDetail && (
        <div>
          <p>このカウンターは、+1 / -1 / リセットの3つの操作ができます。</p>
          <p>State更新の練習用に最適なミニアプリです。</p>
        </div>
      )}
    </div>
  );
}
JSX

ここで起きていることをステップで整理すると、

  1. showDetail はBoolean Stateで、「詳細表示がONかOFFか」を表しています。
  2. toggleDetail では、setShowDetail((prevShowDetail) => !prevShowDetail); として前のStateを反転しています。
  3. ボタンのラベルは、showDetail に応じて「詳細を隠す」「詳細を表示」を切り替えています。
  4. 詳細部分の表示は、{showDetail && (...)} で条件付きレンダリングをしています。

重要ポイント:

  • Boolean Stateは、「機能のON/OFF」「表示のON/OFF」を制御するのに非常に向いています。
  • setShowDetail((prev) => !prev) のような反転更新は、Reactで頻出するパターンです。

カウンターアプリ完成版テンプレート

最後に、数値State・文字列State・Boolean State・前のStateを利用する更新・State更新関数をすべて組み込んだ、カウンターアプリ完成版のテンプレートを示します。

import { useState } from "react";

function CounterApp() {
  // 数値State:カウント
  const [count, setCount] = useState(0);

  // 文字列State:メッセージ
  const [message, setMessage] = useState("まだ何もカウントされていません");

  // Boolean State:詳細表示ON/OFF
  const [showDetail, setShowDetail] = useState(false);

  const updateMessage = (nextCount) => {
    if (nextCount === 0) {
      setMessage("まだ何もカウントされていません");
    } else if (nextCount > 0) {
      setMessage("カウントが進んでいます!");
    } else {
      setMessage("マイナス方向にカウントしています");
    }
  };

  const handleIncrement = () => {
    setCount((prevCount) => {
      const nextCount = prevCount + 1;
      updateMessage(nextCount);
      return nextCount;
    });
  };

  const handleDecrement = () => {
    setCount((prevCount) => {
      const nextCount = prevCount - 1;
      updateMessage(nextCount);
      return nextCount;
    });
  };

  const handleReset = () => {
    const nextCount = 0;
    setCount(nextCount);
    updateMessage(nextCount);
  };

  const toggleDetail = () => {
    setShowDetail((prevShowDetail) => !prevShowDetail);
  };

  return (
    <div>
      <h2>カウンターアプリ</h2>

      <p>現在のカウント:{count}</p>
      <p>メッセージ:{message}</p>

      <button onClick={handleIncrement}>+1</button>
      <button onClick={handleDecrement}>-1</button>
      <button onClick={handleReset}>リセット</button>

      <hr />

      <button onClick={toggleDetail}>
        {showDetail ? "詳細を隠す" : "詳細を表示"}
      </button>

      {showDetail && (
        <div>
          <p>このアプリは、ReactのState更新の基本を練習するためのミニ教材です。</p>
          <p>数値State・文字列State・Boolean Stateを組み合わせて構成されています。</p>
        </div>
      )}
    </div>
  );
}

export default CounterApp;
JSX

DAY 19:カウンターアプリ制作のまとめ

この制作編では、

  • 数値Stateとして count を持ち、+1 / -1 / リセットの動きをState更新関数で定義したこと
  • 「前のStateを利用する」関数型更新(setCount((prev) => prev + 1))を使って、安全に数値を増減させたこと
  • 文字列Stateとして message を持ち、count に応じてメッセージを更新することで、状態に意味を持たせたこと
  • Boolean Stateとして showDetail を持ち、詳細表示のON/OFFを切り替えることで、機能の拡張を表現したこと
  • 数値・文字列・BooleanのStateを1つのアプリの中で組み合わせ、ReactのState更新の基本パターンを実際のUIに落とし込んだこと

をステップバイステップで確認しました。

読者のみなさんが、このカウンターアプリを自分なりに改造してみることで、 State更新の感覚がさらに深く定着していきます。 例えば、「上限・下限をつける」「履歴を表示する」「ボタンを無効化する」など、 少しずつ機能を足していくと、ReactのState設計力が自然と鍛えられていきます。

タイトルとURLをコピーしました