React, Vue.js
投稿日:

AI駆動開発のプロンプト設計術 ─ React/Next.jsで「使えるコード」を引き出す聞き方

こんにちは、株式会社ファストコーディングのフルスタックエンジニア、独身貴族Fireです。

最近、ギターの練習で「Am7のコードを押さえて」とAIに聞いたら、フレットの図が返ってきました。正確だけど、そこじゃない。「初心者がFコードの代わりに使える省略フォームで」と聞き直したら、ちゃんと実用的な回答が来た。

聞き方が曖昧だと、正しいけど使えない答えが返ってくる。コードも同じです。

AI駆動開発において、プロンプトの設計が出力品質の8割を決めると私は考えています。同じClaude、同じCursor、同じCopilotを使っていても、チームメンバーによって出力の質が全く違う。その差はツールの使い方ではなく、「聞き方」にあります。

今回は、React/Next.jsの開発に特化したプロンプト設計のTipsを、実例のBefore/Afterで紹介します。

なぜ「ログインフォームを作って」ではダメなのか

まず、典型的な失敗例から見ていきます。

Bad:漠然としたプロンプト

ログインフォームをReactで作ってください。

AIはこう返してきます。

// AIの出力:動くが「使えない」コード
import { useState } from 'react';

export default function LoginForm() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    console.log({ email, password });
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="Email"
      />
      <input
        type="password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
        placeholder="Password"
      />
      <button type="submit">Login</button>
    </form>
  );
}

構文エラーはない。型も付いている。でもこのコードは案件では使えません。理由は以下の通りです。

  • バリデーションがない(空送信できる)
  • エラー表示がない(ユーザーに何も伝わらない)
  • ローディング状態がない(二重送信のリスク)
  • アクセシビリティ対応がない(labelがない、エラーとフィールドの関連付けがない)
  • APIとの接続がない(console.logで終わっている)

Good:要件を構造化したプロンプト

同じ「ログインフォーム」でも、プロンプトを構造化すると出力が劇的に変わります。

Next.js App Router(TypeScript)でログインフォームを実装してください。

【機能要件】
- メールアドレスとパスワードの入力
- クライアントサイドバリデーション(メール形式チェック、パスワード8文字以上)
- Server Actionでのフォーム送信
- ローディング状態の表示
- エラーメッセージの表示(フィールドごと+フォーム全体)

【非機能要件】
- アクセシビリティ:label、aria-describedby、aria-invalid対応
- UX:touched状態を管理し、未入力フィールドにはエラーを出さない
- スタイル:Tailwind CSSでシンプルに

【制約】
- 外部ライブラリ(react-hook-form等)は使わない
- useActionStateを使用する
- 'use server'ファイルにはasync関数のみexportする

このプロンプトから返ってくるコードは、バリデーション、ローディング、アクセシビリティ、Server Action対応が最初から含まれています。

プロンプト設計の3つの原則

私がReact/Next.js開発でAIを使う際に意識しているプロンプト設計の原則を3つ紹介します。

原則1:「What(何を)」ではなく「Context(文脈)」を伝える

AIに伝えるべき情報は「何を作るか」ではなく、その機能が置かれる文脈です。

伝えるべき項目効果
フレームワーク・バージョンNext.js 15, App Router, TypeScript廃止されたAPIを使わなくなる
データの流れServer Component → Client Componentpropsのシリアライズ制約を考慮する
既存の設計パターンzustandでグローバル状態管理既存アーキテクチャと整合するコードになる
ユーザーの操作フローフォーム入力 → バリデーション → 送信 → リダイレクトUXを考慮した実装になる

たとえば「ドロップダウンメニューを作って」ではなく、こう聞きます。

Next.js App RouterのServer Component内に配置する
ナビゲーションドロップダウンを実装してください。

【文脈】
- ヘッダーのServer Componentから呼ばれるClient Component
- メニュー項目はサーバーから取得済みで、propsとして渡される
- 項目数は最大10件、各項目はlabelとhrefを持つ
- モバイルではハンバーガーメニューに切り替わる(768px以下)

【技術要件】
- 'use client'宣言が必要
- キーボード操作対応(Escape、Arrow Up/Down)
- 外側クリックで閉じる
- Tailwind CSSでスタイリング

この「文脈」があるかないかで、返ってくるコードの実用性が全く違います。Server ComponentとClient Componentの境界を理解した上でのコードが返ってきますし、propsの型もserializable(シリアライズ可能)な形になります。

原則2:「制約」を先に伝える

AIは何も制約を与えないと、「もっともらしいが使えない」コードを出す傾向があります。制約を先に伝えることで、出力の方向性を限定できます。

特にReact/Next.js開発で効果が高い制約は以下の通りです。

【必ず先に伝える制約の例】

❌ 使わないもの:
- 外部ライブラリを使わない(またはXXライブラリのみ使用可)
- class componentは使わない
- anyは使わない

✅ 使うもの:
- App Router(Pages Routerではない)
- Server Actions(API Routeではない)
- useActionState(useFormStateは廃止)
- TypeScript strict mode

⚠️ 気をつけること:
- 'use server'ファイルからはasync関数のみexport可
- Server ComponentからClient Componentにはserializableなpropsのみ渡せる
- Next.js 15ではparamsがPromiseになった

AIが古い情報に基づいたコードを出すのは、こうした制約を伝えていないことが原因です。ReactのuseFormStateuseActionStateにリネームされたこと、paramsがPromiseになったことなど、直近のAPI変更は特に指定しないと古い記法が返ってきます。

原則3:「段階的に」指示を出す

一度に完璧なコードを求めるより、段階的に指示を出す方が品質が高くなります。

ステップ1:型定義から始める

以下の要件のログインフォームを作ります。
まず、必要な型定義(Props、State、Action)だけを出力してください。
コンポーネント本体はまだ不要です。

ステップ2:型をレビューしてからコンポーネントを依頼

型定義をレビューしました。以下の修正を加えます。
(修正内容)

この型に基づいて、コンポーネント本体を実装してください。

ステップ3:テストやエッジケースを追加

実装を確認しました。以下のエッジケースに対応してください。
- パスワードが空白のみの場合
- メールアドレスに日本語が含まれる場合
- API呼び出しがタイムアウトした場合

この段階的なアプローチには2つのメリットがあります。

  1. 各ステップでレビューできる。型定義が間違っていたら、コンポーネント全体を書き直す必要がない
  2. AIのコンテキストが累積する。前のステップで定義した型を次のステップで正しく使ってくれる

一度に「ログインフォームを完璧に作って」と言うと、AIは全部を一回で出そうとして、細部が粗くなります。バイクの組み立てと同じで、フレーム → エンジン → 外装の順に組む方が、完成品の精度は高い。

よくある失敗パターンと対策

失敗1:AIの出力をそのまま使う

AIが出したコードをコピー&ペーストしてそのまま使う。これが最も多い失敗です。

AIの出力はあくまで「たたき台」です。特に以下の点は人間が必ず確認する必要があります。

確認項目よくある問題対策
廃止されたAPIgetServerSideProps(App Routerでは不要)Next.jsの最新ドキュメントと突き合わせる
セキュリティユーザー入力の未サニタイズdangerouslySetInnerHTMLの有無を確認
パフォーマンス不要なuseEffectやre-renderReact DevTools Profilerで確認
型の安全性as any、型アサーションstrict modeでビルドチェック

失敗2:プロンプトが長すぎる

プロンプトに情報を詰め込みすぎると、AIは重要な要件と補足情報を区別できなくなります。

目安として、1つのプロンプトで依頼するのは1つのコンポーネントまで。ページ全体を一度に依頼するのではなく、コンポーネント単位で分割して依頼する方が品質が上がります。

失敗3:「動くコード」で満足する

AIが出したコードがnpm run devで動いた時点で満足してしまう。しかし、「動く」と「使える」は違います。

私が実案件でAIの出力を受け取った後にチェックする項目は以下の通りです。

  1. tsc --noEmitでTypeScriptの型チェックをパスするか
  2. キーボード操作でフォームを送信できるか(Tab → Enter)
  3. スクリーンリーダーで意味が通るか(aria属性、label)
  4. 状態のエッジケース(空入力、長い文字列、ネットワークエラー)

まとめ

今回は、AI駆動開発においてReact/Next.jsで「使えるコード」を引き出すプロンプト設計のTipsを紹介しました。

AIは優秀なジュニアエンジニアのようなものです。明確な要件定義書を渡せば質の高いコードを書いてくれますが、「いい感じに作って」では期待通りのものは出てきません。

プロンプト設計の3つの原則をまとめます。

  1. 「What」ではなく「Context」を伝える。フレームワーク、データの流れ、既存の設計パターン、ユーザーの操作フローを明示する
  2. 「制約」を先に伝える。使わないもの、使うもの、APIの最新変更を最初に指定する
  3. 「段階的に」指示を出す。型定義 → コンポーネント → エッジケース の順に分割して依頼する

AIの出力はたたき台です。最終的な品質を決めるのは、人間のレビューと判断です。ただし、良いたたき台があれば、レビューと修正にかかる時間は大幅に短縮できます。AI駆動開発の真価は、この「たたき台の精度を上げる技術」にあると私は考えています。

株式会社ファストコーディングでは、AI駆動開発を取り入れたフロントエンド実装を行っています。「AI活用で開発効率を上げたい」「React/Next.jsの実装品質を改善したい」という方は、お問い合わせフォームからお気軽にご相談ください。