こんにちは!Reactの学習、楽しく進めていますか?
「画面に文字を入力したら、別の場所にもリアルタイムで反映させたい」「お買い物の合計金額を自動で計算させたい」……そんな風に画面を作っていくうちに、ふとこんな疑問が湧いてくることありませんか?
「あれ? これを表示するためだけに、また `useState` を作らなきゃいけないの……?」
もし、画面に表示するたびに新しい `useState` を用意しようとして手が止まっているなら、ちょっと待った!その悩み、実はReactの現場で誰もが最初に通る「あるある」の壁なんです。
今回は、そんなあなたを救う魔法の考え方「派生状態(Derived State)の計算」について、お買い物のレシートを例にしながら、優しく・深く紐解いていきましょう。大丈夫、一緒にすっきり解決していきましょうね!
—
1. そもそも「派生状態」ってなに? お買い物の例えで考えてみよう
いきなり難しいプログラミング用語が出てくると身構えてしまいますよね。でも、安心してください。考え方はとってもシンプルです。
スーパーでお買い物をしている場面を想像してみてください。
カゴの中に「りんご(300円)」と「みかん(200円)」が入っています。
- 大元のデータ(状態): カゴの中に入っている商品とそれぞれの値段
- 計算して導き出すデータ(派生状態): レジで表示される「合計金額(500円)」
さて、ここで質問です。あなたがお買い物をする時、「りんごは300円、みかんは200円だから……合計金額ボックスという専用のメモ帳を新しく用意して、そこに『500円』と書こう!」とわざわざ別管理しますか?
しませんよね。りんごの値段とみかんの値段が変われば、合計金額は勝手に変わるはずです。
Reactの世界もこれとまったく同じなんです。
「すでにあるデータから計算できるものは、わざわざ新しい `useState` で管理しなくていいんだよ」 というのが、今回のテーマの核心です。
—
2. 初学者がやりがち!「不要な `useState`」のアンチパターン
まずは、Reactを触り始めたばかりの人がやってしまいがちな「ちょっと惜しいコード」を見てみましょう。
今回は、「姓(苗字)」と「名(名前)」を入力すると、自動で「フルネーム」を表示するコンポーネントを作ってみます。
❌ やりがちなコード(すべての値に `useState` を使っちゃう例)
import { useState } from ‘react’;
function BadNameTag() {
// 1. 姓の状態
const [lastName, setLastName] = useState(‘山田’);
// 2. 名の状態
const [firstName, setFirstName] = useState(‘太郎’);
// 3. 🚨【注意】フルネーム専用の「状態」を作っちゃってる!
const [fullName, setFullName] = useState(‘山田 太郎’);
// 姓が変わったときに、フルネームも一緒に更新する関数
const handleLastNameChange = (e) => {
const newLastName = e.target.value;
setLastName(newLastName);
// 忘れずにこっちも更新しなきゃ……あれ?面倒くさいぞ?
setFullName(newLastName + ‘ ‘ + firstName);
};
return (
setFirstName(e.target.value)}
placeholder=”名”
/>
{/ フルネームを表示 /}
こんにちは、{fullName}さん!
);
}
このコード、一見するとちゃんと動くように見えますよね。でも、ここに潜む「見えないバグの芽」に気づけるでしょうか?
もし今後、アプリが大きくなって「名前をリセットするボタン」や「別の場所で姓を変更する処理」が追加されたとき、`setFullName` を更新し忘れるミス(=状態の同期ズレ)が必ずと言っていいほど発生します。「あれ? 苗字を変えたのに、フルネームの表示が古いまま変わらないぞ……?」 という恐怖のバグの誕生です。
—
3. 解決策:レンダリング中に「その場で計算」しちゃおう!
じゃあ、どうすればいいの? 答えは拍子抜けするほど簡単です。
`fullName` 用の `useState` をまるごと消去して、画面を表示する(レンダリングする)直前に、JavaScriptの計算としてその場でサクッと作ってしまいましょう。
これが、「派生状態を `useState` に入れず、直接計算する」 というベストプラクティスです!
⭕ すっきり安全なコード(派生状態の活用)
import { useState } from ‘react’;
function GoodNameTag() {
// 1. 姓の状態(大元のデータ)
const [lastName, setLastName] = useState(‘山田’);
// 2. 名の状態(大元のデータ)
const [firstName, setFirstName] = useState(‘太郎’);
// ✨ 3. useStateは使わず、その場で計算する!これぞ「派生状態」
// 姓や名が変更されてコンポーネントが再描画されるたびに、勝手に最新の値が計算されます
const fullName = `${lastName} ${firstName}`;
return (
placeholder=”姓”
/>
setFirstName(e.target.value)}
placeholder=”名”
/>
{/ 計算された値(派生状態)をそのまま表示するだけ! /}
こんにちは、{fullName}さん!
);
}
どうでしょう? コードがぐっと短くなり、`setFullName` をあちこちで呼び出す必要もなくなりました。これなら「更新し忘れて表示がバグる」という心配が宇宙から消え去りますよね。
—
4. チーフアーキテクトからのアドバイス:迷ったときの判断基準
「じゃあ、どんなときも `useState` を使わずに計算しなきゃいけないの?」と心配になるかもしれませんが、安心してください。判断基準はとっても明快です。
1. そのデータは、すでにある別の状態から「計算」で求められる?
- $\rightarrow$ YESなら、`useState` は不要! (今回のようなフルネームや、配列のアイテム数、合計金額、検索フィルターにかかったリストなど)
2. そのデータは、ユーザーの入力やサーバーからの通信など、外部から直接与えられる「生(なま)のデータ」?
- $\rightarrow$ YESなら、`useState` が必要! (入力フォームの文字、開閉モーダルの `isOpen` フラグなど)
Reactでコードを書くときは、「できるだけ状態(State)の数を減らす」 ことが、バグの少ない、メンテナンスしやすい綺麗なアプリを作る秘訣です。
最初は「本当に `useState` なしで画面が動くの?」と不安になるかもしれませんが、一度このスマートな書き方に慣れると、もう元の冗長なコードには戻れなくなりますよ。
あなたのReact開発が、もっと楽しく、もっと軽やかになりますように。
つまずいたときは、いつでもまたこのブログに帰ってきてくださいね!

コメント