簡単なミニアプリを作る理由
ここまで、React の「部品」を一通り見てきました。
- JSX
- コンポーネント
- props
- useState(状態管理)
- イベント処理
- 条件分岐
- 配列と map
- コンポーネント分割
いよいよ、これらをまとめて「ちょっとしたアプリ」にしてみます。
一気に“実践モード”になるので、わからなくなったら「どの要素の話だったか」を逆戻りしながら読んで大丈夫です。
ここでは、次の二つを作りながら復習します。
カウンターアプリ
入力+リスト表示アプリ(簡易メモ)
最後に「状態管理をどう使っているか」を整理して、ここまでの総復習にします。
カウンターアプリ
どんなアプリかをイメージする
まずは超定番の「カウンターアプリ」です。
画面に数字がひとつ表示されていて、その下にボタンがある。
ボタンを押すたびに、数字が 1 ずつ増える。
という、シンプルだけど「React の基本」がぎゅっと詰まったアプリです。
使う要素はこの3つです。
useState(状態管理)
onClick(イベント処理)
再レンダリング(state が変わると画面が更新される)
コードを書いてみる
Next.js の app/page.tsx に、次のようなコンポーネントを書いてみてください。
"use client";
import { useState } from "react";
export default function Page() {
const [count, setCount] = useState(0);
function handleIncrement() {
setCount(count + 1);
}
function handleReset() {
setCount(0);
}
return (
<main style={{ padding: "40px", fontFamily: "sans-serif" }}>
<h1>カウンターアプリ</h1>
<p style={{ fontSize: "24px" }}>現在のカウント: {count}</p>
<button
onClick={handleIncrement}
style={{ marginRight: "8px", padding: "8px 16px" }}
>
1 増やす
</button>
<button onClick={handleReset} style={{ padding: "8px 16px" }}>
リセット
</button>
</main>
);
}
TSXここで起きていることを丁寧に分解します。
はじめに useState(0) を呼び出し、count の初期値を 0 にしている。count が「今の値」、setCount が「count を更新するための関数」。handleIncrement では setCount(count + 1) を呼び、ボタンを押すたびに count を 1 増やしている。handleReset では setCount(0) として、カウントを 0 に戻している。{count} の部分に、常に「最新の状態の count」が表示される。
ボタンを押して state が変わるたびにコンポーネントが再レンダリングされ、画面も最新状態になる。
この小さなアプリの中で、
状態管理(useState)
イベント処理(onClick)
JSXでの表示({count})
が一気につながっています。
入力+リスト表示アプリ
作るもののイメージ
次は、少しだけ複雑な「入力+リスト表示」のミニアプリを作ります。
簡易メモアプリのようなものです。
テキストボックスがひとつある。
テキストを入力して「追加」ボタンを押すと、下のリストにメモが追加される。
追加されたメモがどんどんたまっていく。
ここでは、次の要素を全部使います。
useState(文字列の state と、配列の state)
onChange(入力値の取得)
onClick(ボタンの処理)
map(配列を画面に表示)
コードを書いてみる
app/page.tsx を次のようにしてみましょう(カウンターとは別のページでもOKです)。
"use client";
import { useState } from "react";
export default function Page() {
const [text, setText] = useState("");
const [memos, setMemos] = useState<string[]>([]);
function handleChange(event: React.ChangeEvent<HTMLInputElement>) {
setText(event.target.value);
}
function handleAdd() {
if (!text.trim()) {
return;
}
setMemos([...memos, text]);
setText("");
}
return (
<main style={{ padding: "40px", fontFamily: "sans-serif" }}>
<h1>簡易メモアプリ</h1>
<div style={{ display: "flex", gap: "8px", marginBottom: "16px" }}>
<input
value={text}
onChange={handleChange}
placeholder="メモを入力..."
style={{ flex: 1, padding: "8px" }}
/>
<button onClick={handleAdd} style={{ padding: "8px 16px" }}>
追加
</button>
</div>
<section>
<h2>メモ一覧</h2>
{memos.length === 0 ? (
<p>まだメモがありません。</p>
) : (
<ul>
{memos.map((memo, index) => (
<li key={index}>{memo}</li>
))}
</ul>
)}
</section>
</main>
);
}
TSX何をしているのかをじっくり整理する
このコンポーネントの中では、状態が二つあります。
入力中の文字を持つ text
追加されたメモ一覧を持つ memos
それぞれの役割はこうです。
text は、入力欄 (<input>) の中身とつねに同期している。memos は、これまでに追加されたメモの配列。
動きの流れを追ってみます。
画面表示時text は空文字(””)、memos は空配列([])でスタート。
「まだメモがありません。」と表示される。
文字入力
ユーザーが入力すると、onChange={handleChange} により handleChange が呼ばれる。event.target.value から現在の入力値を取り出し、setText で text state を更新。
コンポーネントが再レンダリングされ、value={text} の部分に最新の文字が表示される。
追加ボタンクリックonClick={handleAdd} によって handleAdd が呼ばれる。
空文字や空白だけなら何もしない(if (!text.trim()) return;)。setMemos([...memos, text]) で、既存の memos の末尾に text を追加。setText("") で入力欄をクリア。
再レンダリングmemos に値が入ったので memos.length === 0 が false になる。<ul> の中で memos.map(...) が実行され、メモの配列がリストとして表示される。
ここで使っている考え方は、すべてこれまで学んできたものの組み合わせです。
useState で「今の状態」を持つ
イベント(onChange / onClick)で state を更新する
状態に応じて JSX の表示を条件分岐する(三項演算子)
配列を map で JSX のリストに変換する
このミニアプリを理解できれば、React の基本はかなりしっかり掴めています。
状態管理の復習
どんな値が state になるのか
state は「変わる可能性のある値」でした。
カウンターでは count が state。
メモアプリでは、text(入力中の文字)と memos(メモのリスト)が state。
ポイントは、「ユーザーの操作やアプリの進行によって変わるものは state にする」という感覚です。
逆に、次のようなものは state にしません。
固定のタイトル文字列
変わらないラベル(ボタンの文言など)
計算式から常に求められる派生値(必要なときに計算すればよいもの)
「変わるものだけを state にする」と決めることで、コードがシンプルになります。
state 更新 → 再レンダリング → UI 更新
React の大本の動きは、常にこのサイクルです。
state を宣言する
state を使って「こういう UI です」と JSX で宣言する
イベントなどを通じて setState で値を更新する
React がコンポーネントを再実行して、新しい state に基づく JSX を描画する
自分で DOM をいじらないことが、React の美味しいところです。
「今の状態からすると UI はこうあるべきだ」と宣言するだけで、あとの更新は React が面倒を見てくれます。
ここまでの総整理
1. JSX
JavaScript の中で HTML っぽく UI を表現できる。{} で JavaScript の値(変数、計算結果、関数の戻り値など)を埋め込む。
2. コンポーネント
関数として画面の “部品” を定義する。
ひとつのコンポーネントはひとつの UI のまとまりを表す。return の中で JSX を返し、それが画面に表示される。
3. props
親コンポーネントから子コンポーネントへデータを渡す仕組み。
関数の引数のようなイメージで、<Child name="太郎" /> → function Child({ name }) のように受け取る。
4. useState(状態管理)
変わる値を管理するための仕組み。const [value, setValue] = useState(初期値) の形で使う。setValue を呼ぶと state が変わり、コンポーネントが再レンダリングされて UI も更新される。
5. イベント処理
onClick や onChange などで「いつ関数を呼ぶか」を指定する。
onClick などには「関数そのもの」を渡す(onClick={handleClick})。
6. 条件分岐表示
if 文は JSX の外で使う。
JSX の中では三項演算子 {条件 ? A : B} や 条件 && A で表示を切り替える。
7. 配列と map
配列のデータを map で JSX に変換し、リストとして表示する。
リスト要素には key を付ける(基本は一意な id)。
8. コンポーネント分割
大きくなってきたコンポーネントを「意味のある単位」で小さく分ける。
親が全体の構造とデータを管理し、子が表示や小さな動きを担当する。
次に進むためのヒント
ここまで来たら、もう「React で小さいアプリを自分で作れる」レベルは十分見えています。
あとは、
自分でテーマをひとつ決めて(Todo、買い物リスト、簡易家計簿など)
今学んだ要素(state、props、イベント、map…)を組み合わせて
少しずつ機能を足していく
というプロセスで、理解がどんどん「手応え」に変わっていきます。

