はじめに
こんにちは。
Reactを学びたての初学者の者です。
Reactの超基本を学習後、どうやってアウトプットしていこうかと考えていたところ、以下のような先駆者様方の記事を見つけました。
とても参考になりました。
生成AIで問題集を作成できるとは、すごい時代ですね。
やってみた
今回は次のようなプロンプトを投げてみました。
Reactプログラミング初級者です。
Reactの中級者になるための問題集を1問ずつ作成してください。
流れは下記に準じてください。
Step1:
問題は以下の条件で1問ずつ出題する。
・Reactはversion19を使用する
・問題名を表示する
・問題ごとに小さなアプリを作成できるようにする
・問題ごとに正解となる要件を明確に示す(実装する機能など)
・その問題で身に着けるべきこと、学習できることを示す
・問題ごとにヒントも示す
Step2:
私が「ヒントを追加して」「答えを教えて」と指示を出すと、ヒントや解答を示す。
Step3:
私が「解答終了」と指示を出すと、次の問題を出題する。
補足
以後、この記事の流れは以下のようになります。
- ChatGPTが出題した内容
- 私が作成した解答
以後問題14まで繰り返し
1のヒントと2に関しては折りたたんでいます。
私と同じようなアウトプットのやり方に悩んでいる初学者の方の参考になればと思います。
注意
学習中の身のため、解答に冗長な部分があると思いますがご了承ください。
動くことは確認済みです。
また、解答のindex.htmlとエントリーポイントは省略しております。
問題 1:カウンターアプリを作成しよう
📌 問題名
カウンターアプリ
📌 正解となる要件(実装する機能)
-
+ボタンをクリックするとカウントが1増える -
-ボタンをクリックするとカウントが1減る - カウントの値は画面に表示される
- カウントの初期値は0
- カウントの値はコンポーネントの状態(state)で管理する
🎯 学習できること
- React 19の
useStateの使い方 - イベントハンドラーの設定方法(onClickなど)
- JSXの基本的な構文
- 関数コンポーネントの構造
💡 ヒント
- React 19では従来通りの
useStateが使用できます - 状態(state)を管理するために、
useStateをimportしてください - イベントハンドラーに関数を設定することで、クリック時の動作を指定できます
- 状態の更新は関数の引数として新しい値を渡す方法でも可能です
作成した解答
import React, { useState } from "react";
export default function App() {
const [count, setCount] = useState(0);
const handlePlus = () => {
setCount(count + 1);
};
const handleMinus = () => {
setCount(count - 1);
};
return (
<>
<div>count:{count}</div>
<button onClick={handlePlus}>+</button>
<button onClick={handleMinus}>-</button>
</>
);
}
問題 2:テキスト入力フィールドと表示を連動させよう
📌 問題名
リアルタイム文字表示アプリ
📌 正解となる要件(実装する機能)
- ユーザーが入力できるテキストフィールドを1つ作成する
- 入力中のテキストが、画面上にリアルタイムで表示される
- 入力値は状態(state)で管理される
🎯 学習できること
-
input要素の使用方法 - フォーム要素の状態管理(controlled components)
-
onChangeイベントの扱い方 - 状態と表示のリアクティブな連携
💡 ヒント
- テキストの入力内容は
event.target.valueで取得できます -
useStateで入力内容を管理しましょう -
inputのvalue属性に状態変数を指定すると、状態と入力が連動します
作成した解答
import React, { useState } from 'react'
export default function App() {
const [text, setText] = useState("");
const handleChange = (e) => {
setText(e.target.value);
};
return (
<input type="text" placeholder='テキストを入力' value={text} onChange={handleChange} />
)
}
問題 3:条件によって表示を切り替えよう
📌 問題名
ログイン状態によるメッセージ表示アプリ
📌 正解となる要件(実装する機能)
- 「ログイン」「ログアウト」ボタンを作成する
- 初期状態は「ログアウト」状態
- 状態(state)によって画面に表示されるメッセージを切り替える
- ログイン状態のとき:「ようこそ、ユーザーさん!」
- ログアウト状態のとき:「ログインしてください」
- ボタンを押すと、状態がトグル(交互に切り替わる)される
🎯 学習できること
- 状態によってUIを動的に変える方法(条件レンダリング)
- 状態のトグル(真偽値の切り替え)
- JSX内での
ifまたは三項演算子による条件文期の使い方
💡 ヒント
- ログイン状態は
boolean(true/false)で管理できます - 状態の切り替えには
setState(prev => !prev)のような形が便利です - JSX内では
{isLoggedIn ? "..." : "..."}のように条件分岐が書けます
作成した解答
import React, { useState } from "react";
export default function App() {
const [isLoggedIn, setIsLoggedIn] = useState(false);
const handleClick = () => {
setIsLoggedIn((prev) => !prev);
};
return (
<>
<div>
{isLoggedIn ? "ようこそユーザーさん!" : "ログインしてください"}
</div>
{isLoggedIn ? (
<button onClick={handleClick}>ログアウト</button>
) : (
<button onClick={handleClick}>ログイン</button>
)}
</>
);
}
問題 4:配列データをリスト表示しよう
📌 問題名
Todoリストの一覧表示アプリ(表示のみ)
📌 正解となる要件(実装する機能)
-
以下のような初期のTodoデータを配列で持つ:
const todos = [ { id: 1, title: "買い物に行く" }, { id: 2, title: "宿題をやる" }, { id: 3, title: "運動する" } ]; -
この配列を画面上にリストとして表示する
-
各Todoアイテムのタイトルだけが表示される
-
ulとliタグを使って、整ったリストにする
🎯 学習できること
- 配列データを
map()で繰り返し描画する方法 - JSXでの
key属性の重要性と使い方 - Reactでのリスト表示の基本
💡 ヒント
-
todos.map(todo => <li key={todo.id}>{todo.title}</li>)のように書けます - 各要素に
key属性を設定することで、Reactがリストの再描画を正しく処理できます - 配列はコンポーネントの外でも中でも定義できます
作成した解答
export default function App() {
const todos = [
{ id: 1, title: "買い物に行く" },
{ id: 2, title: "宿題をやる" },
{ id: 3, title: "運動する" },
];
return (
<ul>
{todos.map((todo) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
);
}
問題 5:入力フォームからTodoを追加しよう
📌 問題名
Todo追加アプリ(入力+リスト表示)
📌 正解となる要件(実装する機能)
- ユーザーがTodoを入力できる
inputフィールドを1つ作成する - 「追加」ボタンをクリックすると、新しいTodoがリストに追加される
- 追加後、
inputの中身は空になる - Todoは
ulリストで表示される - 各Todoはオブジェクトとして
idとtitleを持つ形で状態に保存される
🎯 学習できること
- フォームの入力状態管理(Controlled Component)
- 状態に配列を使用し、要素を追加する方法
- フォーム送信イベントの処理
- ユーザー操作による状態の更新
💡 ヒント
- 新しいTodoはスプレッド構文(
[...])で既存のリストに追加できます -
idはDate.now()などで簡易的に生成できます -
inputの値は状態で管理し、onChangeで更新しましょう
作成した解答
import React, { useState } from "react";
export default function App() {
const [text, setText] = useState("");
const [todos, setTodos] = useState([]);
const handleChange = (e) => {
setText(e.target.value);
};
const onClickAdd = () => {
const date = Date.now();
const newTodos = [
...todos,
{
id: date,
title: text,
},
];
setTodos(newTodos);
setText("");
};
return (
<>
<input
type="text"
placeholder="todoを入力"
value={text}
onChange={handleChange}
/>
<button onClick={onClickAdd}>追加</button>
<ul>
{todos.map((todo) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
</>
);
}
問題 6:Todoを削除できるようにしよう
📌 問題名
Todo削除アプリ
📌 正解となる要件(実装する機能)
- 各Todo項目の横に「削除」ボタンを表示する
- 「削除」ボタンを押すと、そのTodoがリストから削除される
- 削除後のリストが即時に画面に反映される
- Todoリストは
idを使って一意に管理する
🎯 学習できること
- イベントにパラメータを渡す方法(例:どのTodoを削除するか)
- 配列の
filter()を使って特定の要素を取り除く方法 - JSX内での繰り返しレンダリングとイベント設定の組み合わせ
💡 ヒント
- 削除処理では、
filter(todo => todo.id !== 削除対象のid)が使えます -
onClick={() => handleDelete(todo.id)}のように書くことで、特定のidを削除できます - 状態を更新すれば画面も自動で更新されます(Reactの再レンダリング)
作成した解答
import React, { useState } from "react";
export default function App() {
const [text, setText] = useState("");
const [todos, setTodos] = useState([]);
const handleChange = (e) => {
setText(e.target.value);
};
const onClickAdd = () => {
const date = Date.now();
const newTodos = [
...todos,
{
id: date,
title: text,
},
];
setTodos(newTodos);
setText("");
};
const onClickDelete = (id) => {
setTodos(todos.filter((todo) => todo.id !== id));
};
return (
<>
<input
type="text"
placeholder="todoを入力"
value={text}
onChange={handleChange}
/>
<button onClick={onClickAdd}>追加</button>
<ul>
{todos.map((todo) => (
<li key={todo.id}>
{todo.title}
<button onClick={() => onClickDelete(todo.id)}>削除</button>
</li>
))}
</ul>
</>
);
}
問題 7:useEffectを使ってみよう
📌 問題名
ページ読み込み時にデータを取得するアプリ(モック)
📌 正解となる要件(実装する機能)
-
コンポーネントの初回マウント時(ページ読み込み時)に、
useEffectを使ってデータを取得する -
データは以下のような配列(モック)を1秒後に取得したように見せる(setTimeoutを使用):
const mockData = [ { id: 1, title: "サンプル1" }, { id: 2, title: "サンプル2" } ]; -
データ取得中は「読み込み中...」と表示する
-
データ取得後、リスト表示する
🎯 学習できること
-
useEffectの基本的な使い方 - 非同期処理のシミュレーション(
setTimeout) - 状態の初期化と更新
- 条件付きレンダリング(ローディング表示)
💡 ヒント
-
useEffect(() => { ... }, [])は初回マウント時に一度だけ実行されます - データ取得中は、
isLoadingというbooleanの状態を使って制御できます -
setTimeoutを使うとAPI風の非同期処理を模擬できます
作成した解答
import React, { useEffect, useState } from "react";
const mockData = [
{ id: 1, title: "サンプル1" },
{ id: 2, title: "サンプル2" },
];
export default function App() {
const [isLoading, setIsLoading] = useState(null);
const [data, setData] = useState([]);
useEffect(() => {
setTimeout(() => {
setData(mockData);
setIsLoading(true);
}, 1000);
}, []);
return (
<>
{isLoading ? (
<ul>
{data.map((datum) => (
<li key={datum.id}>{datum.title}</li>
))}
</ul>
) : (
<p>読み込み中...</p>
)}
</>
);
}
問題 8:複数のstateを管理しよう
📌 問題名
カウント&メモ表示アプリ
📌 正解となる要件(実装する機能)
-
「カウント」と「メモ」の2つの情報を入力・表示できるようにする
-
以下の2つの状態をそれぞれ管理する:
- カウント(
+ボタンで1ずつ増加) - メモ(テキスト入力フィールドで入力)
- カウント(
-
それぞれの値は画面に表示される
-
カウントとメモは別々の
useStateで管理する
🎯 学習できること
- 複数の状態(state)の独立管理
- 状態を組み合わせたUIの構成
- 状態が多くなっても明確に構造化する工夫
💡 ヒント
-
useStateは1つのコンポーネント内で複数回使うことができます -
const [count, setCount] = useState(0);
const [memo, setMemo] = useState("");のように使いましょう - JSXの中でそれぞれの状態を適切に表示させることが大切です
作成した解答
import React from "react";
import { useState } from "react";
export default function App() {
const [count, setCount] = useState(0);
const [text, setText] = useState("");
const handleClick = () => {
setCount(count + 1);
};
const handleChange = (e) => {
setText(e.target.value);
} ;
return (
<>
<div>
カウント:{count}
<button onClick={handleClick}>+</button>
</div>
<div>
メモ:
<input type="text" placeholder="メモを入力" value={text} onChange={handleChange}/>
</div>
</>
);
}
問題 9:子コンポーネントにpropsを渡そう
📌 問題名
プロフィール表示コンポーネントの作成
📌 正解となる要件(実装する機能)
- 親コンポーネントから
nameとageの情報を子コンポーネントに渡す - 子コンポーネントは受け取った
nameとageを画面に表示する - 表示内容の例:
名前:田中太郎 / 年齢:25歳 - propsの受け取り方を正しく理解して使う
🎯 学習できること
-
propsの基本的な使い方 - 親から子へのデータの受け渡し
- コンポーネントの分割と再利用性の向上
💡 ヒント
- 子コンポーネントは、引数として
propsまたは{ name, age }のように受け取れます - 親で
<Profile name="田中太郎" age={25} />のように渡しましょう - 分割代入を使うと見やすくなります:
function Profile({ name, age }) { ... }
作成した解答
import React from 'react'
import Children from './Children'
export default function App() {
return (
<Children name={"田中太郎"} age={25} />
)
}
import React from 'react'
export default function Children({ name, age }) {
return (
<>
<div>名前:{name}</div>
<div>年齢:{age}歳</div>
</>
)
}
問題 10:親コンポーネントから子コンポーネントへイベント関数を渡そう
📌 問題名
子コンポーネントからカウントを増やすボタンを押すアプリ
📌 正解となる要件(実装する機能)
- 親コンポーネントで
countを状態として管理する - 子コンポーネントに「カウントを増やす」ボタンを配置する
- 子コンポーネントでボタンがクリックされると、親の
countが1増える - カウントの値は親コンポーネントで表示する
🎯 学習できること
- コールバック関数をpropsとして渡す方法
- 子コンポーネントから親の関数を呼び出す仕組み
- 状態リフトアップ(状態を親に保持し、子で操作)
💡 ヒント
- 親で
handleIncrement関数を定義し、それを子にonIncrementとして渡します - 子では
onClick={onIncrement}のように使います - 状態は必ず親で管理し、子では変更の「きっかけ」だけを作るようにします
作成した解答
import React, { useState } from "react";
import Children from "./Children";
export default function App() {
const [count, setCount] = useState(0);
const handleIncrement = () => {
setCount(count + 1);
};
return (
<>
<div>カウント:{count}</div>
<Children onIncrement={handleIncrement} />
</>
);
}
import React from 'react'
export default function Children({ onIncrement }) {
return (
<button onClick={onIncrement}>カウントを増やす</button>
)
}
問題 11:チェックボックスで状態を切り替えよう
📌 問題名
Todoの完了状態をチェックできるアプリ
📌 正解となる要件(実装する機能)
- 複数のTodo項目(id, title, completed)を状態として保持する
- 各Todoの横にチェックボックスを表示する
- チェックボックスをクリックすると、そのTodoの
completed状態(true/false)がトグルされる -
completed: trueのTodoは文字が取り消し線(text-decoration: line-through)で表示される
🎯 学習できること
- チェックボックスの扱い方(
checkedとonChange) - 状態の配列を更新する方法(特定の項目だけ書き換え)
- 条件に応じてCSSスタイルを動的に変更する方法
💡 ヒント
- チェック状態は
checked={todo.completed}で制御できます -
onChangeで該当のTodoのcompleted値を反転させましょう - 条件付きでスタイルを適用するには、インラインで
style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}のように書けます
作成した解答
import React from "react";
import { useState } from "react";
export default function App() {
const [todos, setTodos] = useState([]);
const [text, setText] = useState("");
const handleChangeText = (e) => {
setText(e.target.value);
};
const onClickAdd = () => {
const date = Date.now();
setTodos([...todos, {
id: date,
title: text,
isCompleted: false,
}]);
setText("");
};
const handleChangeCheckbox = (id) => {
const updateTodos = todos.map((todo) =>
todo.id === id ? { ...todo, isCompleted: !todo.isCompleted } : todo
);
setTodos(updateTodos);
};
return (
<>
<input
type="text"
placeholder="todoを入力"
value={text}
onChange={handleChangeText}
/>
<button onClick={onClickAdd}>追加</button>
<div>
<p>todo一覧</p>
<ul>
{todos.map((todo) => (
<li key={todo.id}>
<span
style={{
textDecoration: todo.isCompleted ? "line-through" : "none",
}}
>
{todo.title}
</span>
<input
type="checkbox"
onChange={() => handleChangeCheckbox(todo.id)}
checked={todo.isCompleted}
/>
</li>
))}
</ul>
</div>
</>
);
}
問題 12:フォームの送信を防いで処理しよう
📌 問題名
送信イベント処理アプリ
📌 正解となる要件(実装する機能)
- フォーム内に
inputとbuttonを1つずつ作成する - ボタンをクリック(またはEnterキーで送信)すると、フォームの送信イベントが発生する
- 送信イベントを防止し、ページのリロードをさせない
- 入力内容を取得し、画面に表示する
🎯 学習できること
- フォーム送信イベント(
onSubmit)の処理方法 -
event.preventDefault()の重要性 -
formタグとinput/buttonの連携
💡 ヒント
-
formタグにonSubmit={handleSubmit}を設定しましょう -
handleSubmit関数内でevent.preventDefault()を呼ぶことで、ページの再読み込みを防げます - 入力値は
useStateで管理し、送信時にその内容を表示すればOKです
作成した解答
import React from 'react'
import { useState } from 'react'
export default function App() {
const [text, setText] = useState("");
const [show, setShow] = useState("");
const handleChange = (e) => {
setText(e.target.value);
};
const handleSubmit = (e) => {
e.preventDefault();
setShow(text);
setText("");
};
return (
<>
<form onSubmit={handleSubmit}>
<input type="text" placeholder='テキストを入力' value={text} onChange={handleChange}/>
<button>送信</button>
</form>
<div>
最新の入力:{show}
</div>
</>
)
}
問題 13:ラジオボタンで選択肢を切り替えよう
📌 問題名
好きな色を選ぶフォームアプリ
📌 正解となる要件(実装する機能)
- 「赤」「青」「緑」の3つのラジオボタンを用意する
- ユーザーが1つを選ぶと、その色名が画面に表示される
- ラジオボタンの選択状態は
useStateで管理する - ラジオボタンの値と
checked状態を正しく連動させる
🎯 学習できること
-
input type="radio"の使い方 - ラジオボタンのグルーピングと
name属性の重要性 - 選択肢の状態を1つのstateで管理する方法
💡 ヒント
-
各
inputにvalueを設定し、状態とcheckedを連動させましょう -
例:
<input type="radio" name="color" value="赤" checked={selectedColor === "赤"} onChange={(e) => setSelectedColor(e.target.value)} /> -
複数の選択肢があっても、状態は1つで十分です
作成した解答
import React from "react";
import { useState } from "react";
export default function App() {
const [selectedColor, setSelectedColor] = useState(null);
return (
<>
<h1>選んだ色:{selectedColor}</h1>
<input
type="radio"
id="red"
name="color"
value={"赤"}
checked={selectedColor === "赤"}
onChange={(e) => setSelectedColor(e.target.value)}
/>
<label htmlFor="red">赤</label>
<input
type="radio"
id="blue"
name="color"
value={"青"}
checked={selectedColor === "青"}
onChange={(e) => setSelectedColor(e.target.value)}
/>
<label htmlFor="blue">青</label>
<input
type="radio"
id="green"
name="color"
value={"緑"}
checked={selectedColor === "緑"}
onChange={(e) => setSelectedColor(e.target.value)}
/>
<label htmlFor="green">緑</label>
</>
);
}
問題 14:selectタグで選択肢を切り替えよう
📌 問題名
国を選ぶセレクトボックスアプリ
📌 正解となる要件(実装する機能)
- セレクトボックス(
<select>)で「日本」「アメリカ」「フランス」から1つを選べるようにする - 選択された国の名前を画面に表示する
- 選択状態は
useStateで管理する -
onChangeイベントを使って選択肢の変更に対応する
🎯 学習できること
-
<select>と<option>の使い方 - フォーム要素の状態管理(controlled component)
- 選択肢の変更に応じて画面表示を更新する方法
💡 ヒント
-
selectタグにはvalue属性を設定し、状態と連動させます -
onChange={e => setSelectedCountry(e.target.value)}のようにして状態を更新します -
optionにはそれぞれ異なるvalueを設定しておきましょう
作成した解答
import React from 'react'
import { useState } from 'react'
export default function App() {
const [selectedCountry, setSelectedCountry] = useState("");
const handleChange = (e) => {
setSelectedCountry(e.target.value);
};
return (
<>
<h1>選んだ国名:{selectedCountry}</h1>
<select value={selectedCountry} onChange={handleChange}>
<option value="">国を選んでください</option>
<option value="日本">日本</option>
<option value="アメリカ">アメリカ</option>
<option value="フランス">フランス</option>
</select>
</>
)
}
終わりに
今回14問で終わっているのは訳がありまして、15問目を出力したところ、既に解答済みの問題とほぼ同様の問題でした。
そこで
まだ出題していない内容の問題をお願いします。
もし初級者のレベルを卒業したと判断できたら、中級者向けの問題を出題してください。
と投げてみたところ
ご指摘ありがとうございます。そして、おめでとうございます!🎉
あなたはReact初級者レベルをしっかりと卒業できています。これからは中級者向けの問題にステップアップしましょう!
と返ってきました。
ChatGPT的には問題14まで解けたら初級者は卒業みたいです。