このアドベントカレンダーのテーマ
この連載は、
技術初心者・非エンジニアの私が、ChatGPT を相棒にしながら
Next.js で Webアプリ(ブックマークアプリ)を 0 から作り切るまでの 24 日間の記録
です。
よくある
- 「プロンプト投げたらツールが全部やってくれる」
- 「AIにコード書かせてコピペして終わり」
みたいな話ではなく、
- 手を動かすのはあくまで自分
- ChatGPT は先生・相棒・レビュー係
- わからないところを、その場で聞きながら進める
というスタイルで進めていきます。
「非エンジニアでも、ChatGPT をうまく使えば Webアプリ開発ってここまでできるのか」という実録にしたいです。
DAY1から読む↓
今日やること
Day5 のテーマは 「はじめてのフォームと、useStateで“入力した値”を扱ってみる」 です。
(useStateってなんだろう…)
Day4 で /bookmarks ページまでは作れたものの、そこで固まっています。何もできていない。体裁をなしているとは言えない。もはやページと呼んでいいかわからない。
今日は ChatGPT に教わりながら、
-
/bookmarksに URL入力フォームを置いてみる - 入力した文字を React の
useStateで持ってみる - 入力した内容をそのまま画面に表示してみる
ところまでを目標にしたらよさそうです。
Step 1. フォームはどう作っていけばよいのか?
Q:Next.js(React)で、URLを入力するフォームってどう書けばいいの?ちなみに私はHTMLのこともよくわからなから、HTMLなら~って書くのはやめてね。
ChatGPT の回答(要約):
了解!
HTML を前提にしないで、Next.js(React)だけの文脈で“URL入力フォーム”をゼロから説明するね。
初心者がいちばん混乱するポイントを全部避けつつ、
「これを書けばとりあえず動く」形に落とした 最小の例 でいくよ。
🎯 結論:まずはこれを書けば「URL入力フォーム」が動きます
"use client";
import { useState } from "react";
export default function BookmarkForm() {
const [url, setUrl] = useState("");
return (
<div>
<h2>URLを追加する</h2>
<input
type="text"
value={url}
onChange={(e) => setUrl(e.target.value)}
placeholder="URLを入力してください"
/>
<button onClick={() => alert(url)}>追加</button>
</div>
);
}
📌 このコードが何をしているのか(Reactだけで理解できるように説明)
① use client が必要な理由
Next.js の app/ 配下はデフォルトで「サーバー側で動く」仕組み。
でも フォームは“画面側”で動く必要がある。
だから、このページはクライアント側で動かすよ!という印になるのが:
"use client";
これを書くと、React の「動くUI」が使えるモードになる。
② useState で“入力値を覚える”
入力欄に文字を入れたら、Reactはその値をどこかに保存しておく必要がある。
その“保存場所”を作るのが useState。
const [url, setUrl] = useState("");
意味は:
- url → 今の入力値が入る場所
- setUrl → 入力値を更新する関数
初心者向けにすごくシンプルに言うと…
「入力された文字を覚えておく箱を作る」のが useState。
③ <input> に「値を覚えてね」と教える
<input
value={url}
onChange={(e) => setUrl(e.target.value)}
/>
✦ value={url}
→ 入力欄の中身は url(useStateの中身)と同じ にしますよ。
✦ onChange={(e) => setUrl(e.target.value)}
→ ユーザーが入力したら、その文字を setUrl() で保存 しますよ。
これで「入力して → 状態が変わる → Reactが再描画」という基本の流れが成立する。
④ 最後のボタン
<button onClick={() => alert(url)}>追加</button>
ここではまだ DB も API もないので、
とりあえず押したら「入力した値」が見えるようにしてるだけ。
アプリとしては、
- 将来:APIに送る
- 今は:alertで動作確認
という仕組み。
🎉 初心者向けのめちゃシンプルまとめ
-
フォームは クライアントで動くので
use clientが必要 -
入力された文字を保存するには useState を使う
-
<input>に-
value(今の値) -
onChange(変わったときの処理)
をセットすると動く
-
-
まずは入力したものを alert で確認すればOK
📌 じゃあこれをどこに置けばいいの?
次のようにするのが自然:
app/
bookmarks/
page.tsx
BookmarkForm.tsx ← ここに書く
そして page.tsx から読み込む:
import BookmarkForm from "./BookmarkForm";
export default function BookmarksPage() {
return (
<main>
<h1>Bookmarks Page</h1>
<BookmarkForm />
</main>
);
}
なるほど。
BookmarkForm.tsx を作成し、上記のコードを入れて、page.tsxも上書きする。
書き込める「フォーム」らしきものと追加ボタンのようなものができている!
ChatGPTも言っている通り、
とりあえず押したら「入力した値」が見えるようにしてるだけ。
ではあるのだけど。進歩進歩!!
Step 2. 入力した内容を画面に出すには?
入力している内容を、そのまま下の行に表示してみる
ところに進みたいと思います。
BookmarkForm.tsx を少しだけ書き換えます。
"use client";
import { useState } from "react";
export default function BookmarkForm() {
const [url, setUrl] = useState("");
return (
<div>
<h2>URLを追加する</h2>
<input
type="text"
value={url}
onChange={(e) => setUrl(e.target.value)}
placeholder="URLを入力してください"
/>
<button onClick={() => alert(url)}>追加</button>
{/* 入力中の値をそのまま表示してみる */}
<p>今入力しているURL:{url}</p>
</div>
);
}
<p>今入力しているURL:{url}</p> を足しただけ。
フォームに入力中の文字が下にでるようになった!
Q:今何が起きたの?
ChatGPTの回答(要約)
めちゃくちゃ良い質問!! **「1行増やしただけに見えるのに、なんでこんなに“動くUI”になるの?」** ってところが、React の **本質** だから。結論から言うと、
<p>今入力しているURL:{url}</p> を足したことで起きたのは──
🎯 起きたこと(超ざっくり)
“React が、state(url)が変わるたびに自動で画面を書き直すようになった”
ただそれだけ。
でもその「書き直し」の仕組みこそが React のコア機能。
🧠 実際にはこんな流れが起きている
① 入力欄に文字を打つ
ユーザーが例えば「https://aaa」と入力。
② onChange が発動する
onChange={(e) => setUrl(e.target.value)}
この瞬間、
setUrl("https://aaa") が呼ばれて url が更新 される。
③ useState が「値が変わった」とReactに教える
Reactは内部で
“あ、url が変わったな。じゃあこのコンポーネントを描き直すか”
と判断する。
④ React が BookmarkForm 全体を丸ごと再レンダリング
つまり、
BookmarkForm の関数が もう一度実行される。
↓ だから、この部分にも最新の値が入る:
<p>今入力しているURL:{url}</p>
⑤ 表示が最新状態に変わる
だから
入力欄に「h」と打てば {url} は「h」になり、
「ht」と打てば {url} は「ht」に変わる。
以上!
🎉 つまり、たった1行で“ライブ表示の仕組み”が完成した理由
理由はこれひとつ:
Reactが状態(state)の変化に応じて画面を自動で作り直すから。
あなたがやったのは:
- state(url)を画面に表示するコードを書いた
- onChange で state を更新するコードを書いた
React が勝手に
- 値が変わったら、必要な部分を更新してくれる
という仕掛けまですべて面倒を見てくれる。
Step 3. 「追加ボタンを押した瞬間の値」も覚えてみる
入力中の値が表示できたので、次に必要なのは「追加ボタンを押した瞬間の値」のようです。
- 入力しているとき →
{url}がリアルタイムで更新される - 追加ボタンを押したとき → その時点のURLを別で覚えておきたい
という状態にしたい。
BookmarkForm.tsx を少し拡張する。
"use client";
import { useState } from "react";
export default function BookmarkForm() {
const [url, setUrl] = useState("");
const [submittedUrl, setSubmittedUrl] = useState("");
const handleClick = () => {
if (!url.trim()) return; // 空文字だったらスルー
setSubmittedUrl(url); // ボタンを押した瞬間の値を覚える
setUrl(""); // 入力欄をクリアする
};
return (
<div>
<h2>URLを追加する</h2>
<input
type="text"
value={url}
onChange={(e) => setUrl(e.target.value)}
placeholder="URLを入力してください"
/>
<button type="button" onClick={handleClick}>
追加
</button>
<p>今入力しているURL:{url}</p>
{submittedUrl && (
<p>最後に追加したURL:{submittedUrl}</p>
)}
</div>
);
}
Q:今のは何が起こった?
ChatGPTの回答(要約)
めちゃくちゃ良い視点!!! これも **React という仕組みの大事なポイント** に触れてるので、 初心者が理解したら一気にレベルが上がる部分です。結論から言うと、
あなたが書いたこのコード:
{submittedUrl && (
<p>最後に追加したURL:{submittedUrl}</p>
)}
が追加されたことで起きているのは──
🎯 「値があるときだけ表示する」という“条件つきUI”が動くようになった
この一行(正確には3行)を追加したことで、
- submittedUrl が 空文字のとき → 何も表示しない
- submittedUrl に 値が入った瞬間 →
が表示される
という「見たり消えたりするUI」が完成した。
これが React の条件レンダリング と呼ばれる仕組み。
🧠 実際にはこういう流れが起きている
① 初期状態:submittedUrl は空
const [submittedUrl, setSubmittedUrl] = useState("");
最初は ""(空文字)なので…
"" && (<p>〜</p>)
これは JavaScript のルールで false と扱われる。
だから 何も表示されない。
画面は静か。
② 「追加」を押すと setSubmittedUrl(url) が実行される
例えば https://example.com を追加したとすると…
submittedUrl は "https://example.com" になる。
これが truthy(=true扱い)。
③ React が「状態が変わった!」と気づいて再描画する
BookmarkForm がもう一度実行され、
"https://example.com" && (<p>最後に追加したURL: https://example.com</p>)
これは true なので <p> の中身がそのまま画面に描かれる。
④ 結果:「最後に追加したURL:…」が表示される
🎉 本質:React の “レンダリング = ただの if 文の世界”
条件レンダリングは実は「ただの if 文」と同じで、
- true → 表示
- false → 表示しない
というだけ。
でも React の凄いところは、
state が変わるたびに、勝手にこの条件式をもう一度評価して、UIを作り直してくれる
という点。
あなたがやったのはただの1行の追加なのに、
React が裏で
- state の変化を検知して
- コンポーネント全体を再計算して
- 必要なところだけ差し替えて
…というめちゃくちゃ重い仕事を代わりにやってくれている。
なんかどんどん難しくなるな?ついていける気がしないぞ…
Reactが、とか、Next.jsが、とかじゃなくて、プログラミングの難しさに打ちひしがれている。
Day5 の締め:今日できたこと・明日やること
今日できたこと
-
/bookmarksにフォームを設置できた - useState を使って「入力中の値」を扱えるようになった
- 入力した内容をそのまま画面に出すことができた
- 追加ボタンを押したタイミングの値も別 state に保存できた
- React が“状態の変化に反応してUIを描き直す”ことを体験できた
これ本当にあと20日で終わりそう??
明日やること(Day6)
Day6 では、今日の延長線上でもう一歩進めて、
- URL を「1件」ではなく 配列で複数管理する
- 配列を
mapで並べて「ブックマーク一覧っぽいもの」を表示する - 今後 API に送るための“準備運動”をしていく
いよいよ “ブックマークアプリ” の姿が少し見えてくる…のか⁉


