PerplexityでAI駆動開発:Reactでサクッと入力フォーム画面をつくる

こんにちは。
今日はベビーの一ヶ月検診でした。
私は産院に入れないので入口まで見届けて、スタバでカタカタしていました。

さて、前回までの記事ではPerplexityでVite×React×TestingLibraryの環境を立ち上げました。

今回は、もう少し踏み込んでみましょう。
UIライブラリのMUIをインストールして、簡単な入力フォーム画面を作りたいと思います。

目次

MUIをインストールする

では早速、PerplexityにMUIのインストールスクリプトを出してもらいましょう。

Vite, React, TestingLibrary で構築した初期プロジェクトがあります。
ここに簡単な入力フォームの画面を追加したいです。

まず、UIには MUI を使いたいので、インストールスクリプトを提供してください。

今回はこのようにお願いしてみました。

AIにコード生成させるときは、前提を伝えることが大事です。

今回でいうと、この環境は Vite, React, TestingLibrary で構築しているのでその情報を前提として伝えています。

以下のような回答が得られました。

MUIをViteとReactで構築されたプロジェクトに追加するには、以下のコマンドを実行してください:

npm install @mui/material @emotion/react @emotion/styled @mui/icons-material

このコマンドは、MUIの主要パッケージとEmotionスタイリングライブラリ、そしてMUIのアイコンパッケージをインストールします

135。インストールが完了したら、MUIコンポーネントを使用して簡単な入力フォームを作成できます。例えば、App.tsxファイルに以下のようなコードを追加できます:

import React from 'react';
import { TextField, Button, Box } from '@mui/material';

function App() {
return (
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2, maxWidth: 300, margin: 'auto' }}>
<TextField label="名前" variant="outlined" />
<TextField label="メールアドレス" variant="outlined" type="email" />
<Button variant="contained" color="primary">送信</Button>
</Box>
);
}

export default App;

このコードは、名前とメールアドレスの入力フィールドと送信ボタンを含む基本的なフォームを作成します

4。MUIのコンポーネントを使用することで、マテリアルデザインに準拠した美しいUIを簡単に実装できます13

インストールスクリプトだけじゃなく、サンプル画面も作ってくれましたね。
気が利くー

では、提案されたコードを使って、MUIをインストールして画面を立ち上げてみましょう。

MUIが使えて、エラーがなく起動できることが確認できました。

ただ、入力フォームが左に寄ってしまっているので直しておきましょう。

初期構築時に生成される App.css をみると、中央揃えの指定が入っているようでした。

#root {
  max-width: 1280px;
  margin: 0 auto;
  padding: 2rem;
  text-align: center;
}

というわけで、今回は App.css がインポートすればOKです。
このプロジェクトに App.css があることをPerplexityに伝えていなかったので抜けてしまった、ということですね。

import React from 'react';
import { TextField, Button, Box } from '@mui/material';
import "./App.css"

function App() {
  return (
    <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2, maxWidth: 300, margin: 'auto' }}>
      <TextField label="名前" variant="outlined" />
      <TextField label="メールアドレス" variant="outlined" type="email" />
      <Button variant="contained" color="primary">送信</Button>
    </Box>
  );
}

export default App;

中央揃えになっていることが確認できました。

見た目をすこし良くしてみる

これだけでは物足りないので、ついでに画面をすこしだけリッチにしてみましょう。

システム名と入力欄のヘッダーを追加したいと思います。

import React from ‘react’;
import { TextField, Button, Box } from ‘@mui/material’;
import “./App.css”

function App() {
return (
<Box sx={{ display: ‘flex’, flexDirection: ‘column’, gap: 2, maxWidth: 300, margin: ‘auto’ }}>
<TextField label=”名前” variant=”outlined” />
<TextField label=”メールアドレス” variant=”outlined” type=”email” />
<Button variant=”contained” color=”primary”>送信</Button>
</Box>
);
}

export default App;

上記の App コンポーネントを以下のように変更してください。

・ロゴを追加
src/assets/react.svg を使用してください。
システム名は Sample System としてください。

・入力欄にヘッダーを追加してください。
名前は Name のヘッダー。label を 田中 たろう に変更してください
メールアドレスは Mail Address のヘッダー。label を sample@test.com に変更してください

ポイントは、App.tsx のコードを入れていることです。

先ほどApp.css のインポートを手動で追加しましたが、この変更をPerplexityは知らないので、これを入れておかないとインポート文が抜けて、また左寄せに戻ってしまいます。

繰り返しになりますが、「このコードに対して変更を加えてください」という前提を伝えることが大事です。

送信ボタンの onClick 処理を追加する

送信ボタンを押したときの処理がないので、こちらも追加しておきましょう。

今回はサーバーがないので、カスタムフックで簡易的なモックAPIを作ってみたいと思います。

以下のようにPerplexityにお願いしてみました。

送信ボタンを押したときの処理を追加したいです。
以下のフックを作成し、送信ボタンを押したときにフックの戻り値の post関数を実行するよう変更してください。

フック名 useApi
引数 name: string, mail: string
戻り値 post関数
処理 console.log() で ‘名前: ${name}, メールアドレス: ${mail}’ と出力する

関数名 handleClick
 名前とメールアドレスを useApi の戻り値の post関数にわたす

なお、Appコンポーネントの入力欄に name, mail の state がないので追加してください。

以下の回答が得られました。

承知しました。要求に応じて、useApiフックを作成し、Appコンポーネントを修正して、入力値の状態管理と送信ボタンのクリックハンドラを追加します。以下が更新されたコードです:

import React, { useState } from 'react';
import { TextField, Button, Box, Typography } from '@mui/material';
import "./App.css"
import reactLogo from './assets/react.svg'

// useApi フックの定義
const useApi = (name: string, mail: string) => {
  const post = () => {
    console.log(`名前: ${name}, メールアドレス: ${mail}`);
  };
  return { post };
};

function App() {
  const [name, setName] = useState('');
  const [mail, setMail] = useState('');

  const { post } = useApi(name, mail);

  const handleClick = () => {
    post();
  };

  return (
    <Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 2, maxWidth: 300, margin: 'auto' }}>
      <Box sx={{ display: 'flex', alignItems: 'center', gap: 2, marginBottom: 2 }}>
        <img src={reactLogo} alt="React Logo" style={{ width: 50, height: 50 }} />
        <Typography variant="h5" component="h1">Sample System</Typography>
      </Box>

      <Typography variant="h6" component="h2" align="left" sx={{ alignSelf: 'flex-start' }}>Name</Typography>
      <TextField 
        label="田中 たろう" 
        variant="outlined" 
        fullWidth 
        value={name}
        onChange={(e) => setName(e.target.value)}
      />

      <Typography variant="h6" component="h2" align="left" sx={{ alignSelf: 'flex-start', marginTop: 2 }}>Mail Address</Typography>
      <TextField 
        label="sample@test.com" 
        variant="outlined" 
        type="email" 
        fullWidth 
        value={mail}
        onChange={(e) => setMail(e.target.value)}
      />

      <Button 
        variant="contained" 
        color="primary" 
        sx={{ marginTop: 2 }}
        onClick={handleClick}
      >
        送信
      </Button>
    </Box>
  );
}

export default App;

この更新されたコードでは以下の変更を行いました:

  1. useApiフックを作成し、namemailを引数として受け取り、post関数を返すようにしました。
  2. Appコンポーネント内でnamemailのstate管理を追加しました。
  3. TextFieldコンポーネントにvalueonChangeプロパティを追加し、state値の表示と更新を行えるようにしました。
  4. handleClick関数を作成し、送信ボタンがクリックされたときにuseApiフックから返されたpost関数を呼び出すようにしました。
  5. 送信ボタンにonClickイベントハンドラを追加し、handleClick関数を呼び出すようにしました。

これらの変更により、ユーザーが入力フォームに値を入力し、送信ボタンをクリックすると、コンソールに入力された名前とメールアドレスが表示されるようになります。

useApi が作成できているのですが、私はフックは別ファイルに書く派なので修正してもらいます。

useApi は src/hooks/useApi.ts に作りたいです。

承知しました。useApiフックを別のファイルに分離するのは良い方法です。以下のようにsrc/hooks/useApi.tsファイルを作成し、そこにuseApiフックを定義します。

まず、src/hooks/useApi.tsファイルを作成し、以下の内容を記述してください:

// src/hooks/useApi.ts

const useApi = (name: string, mail: string) => {
  const post = () => {
    console.log(`名前: ${name}, メールアドレス: ${mail}`);
  };
  return { post };
};

export default useApi;

次に、App.tsxファイルを以下のように更新します:

import React, { useState } from 'react';
import { TextField, Button, Box, Typography } from '@mui/material';
import "./App.css"
import reactLogo from './assets/react.svg'
import useApi from './hooks/useApi';

function App() {
  const [name, setName] = useState('');
  const [mail, setMail] = useState('');

  const { post } = useApi(name, mail);

  const handleClick = () => {
    post();
  };

  return (
    <Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 2, maxWidth: 300, margin: 'auto' }}>
      <Box sx={{ display: 'flex', alignItems: 'center', gap: 2, marginBottom: 2 }}>
        <img src={reactLogo} alt="React Logo" style={{ width: 50, height: 50 }} />
        <Typography variant="h5" component="h1">Sample System</Typography>
      </Box>

      <Typography variant="h6" component="h2" align="left" sx={{ alignSelf: 'flex-start' }}>Name</Typography>
      <TextField 
        label="田中 たろう" 
        variant="outlined" 
        fullWidth 
        value={name}
        onChange={(e) => setName(e.target.value)}
      />

      <Typography variant="h6" component="h2" align="left" sx={{ alignSelf: 'flex-start', marginTop: 2 }}>Mail Address</Typography>
      <TextField 
        label="sample@test.com" 
        variant="outlined" 
        type="email" 
        fullWidth 
        value={mail}
        onChange={(e) => setMail(e.target.value)}
      />

      <Button 
        variant="contained" 
        color="primary" 
        sx={{ marginTop: 2 }}
        onClick={handleClick}
      >
        送信
      </Button>
    </Box>
  );
}

export default App;

この変更により、useApiフックがsrc/hooks/useApi.tsファイルに分離され、App.tsxファイルでインポートして使用されるようになりました。これにより、コードの構造がより整理され、再利用性も向上します。

いい感じになってきましたね。

ですが、もう1点気になるところがあります。

useApi フックの呼び出し時に引数を渡しているところです。

const { post } = useApi(name, mail);

そして、useApi フックの戻り値の post 関数を実行するときは引数を渡していません。

  const handleClick = () => {
    post();
  };

この状態で画面を操作してみると、問題なく動きはするのですが、この書き方は私は自然ではないと思います。

名前とメールアドレスの入力値は「送信ボタンが押されたら post 関数で送信する」ものだと思うからです。
今のコードだと、「useApi に名前とメールアドレスを渡しておいて、その値を post 関数が実行されたときに送信する」というよくわからない状態になっています。

プログラムを書くときは「わかりやすさ」が大事です。
「引数なしの post 関数を実行したのに、実は名前とメールアドレスが送信されている」という状態は避けたほうがよいでしょう。

というわけで、以下のようにPerplexityに指示して修正してもらいます。

name と mail を useApi の引数に渡していますが、そうではなく、post関数の引数に渡すよう修正してください。

申し訳ありません。ご指摘ありがとうございます。ご要望に沿って修正いたします。

まず、src/hooks/useApi.tsファイルを以下のように更新します:

// src/hooks/useApi.ts

const useApi = () => {
  const post = (name: string, mail: string) => {
    console.log(`名前: ${name}, メールアドレス: ${mail}`);
  };
  return { post };
};

export default useApi;

次に、App.tsxファイルを以下のように修正します:

import React, { useState } from 'react';
import { TextField, Button, Box, Typography } from '@mui/material';
import "./App.css"
import reactLogo from './assets/react.svg'
import useApi from './hooks/useApi';

function App() {
  const [name, setName] = useState('');
  const [mail, setMail] = useState('');

  const { post } = useApi();

  const handleClick = () => {
    post(name, mail);
  };

  return (
    <Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 2, maxWidth: 300, margin: 'auto' }}>
      <Box sx={{ display: 'flex', alignItems: 'center', gap: 2, marginBottom: 2 }}>
        <img src={reactLogo} alt="React Logo" style={{ width: 50, height: 50 }} />
        <Typography variant="h5" component="h1">Sample System</Typography>
      </Box>

      <Typography variant="h6" component="h2" align="left" sx={{ alignSelf: 'flex-start' }}>Name</Typography>
      <TextField 
        label="田中 たろう" 
        variant="outlined" 
        fullWidth 
        value={name}
        onChange={(e) => setName(e.target.value)}
      />

      <Typography variant="h6" component="h2" align="left" sx={{ alignSelf: 'flex-start', marginTop: 2 }}>Mail Address</Typography>
      <TextField 
        label="sample@test.com" 
        variant="outlined" 
        type="email" 
        fullWidth 
        value={mail}
        onChange={(e) => setMail(e.target.value)}
      />

      <Button 
        variant="contained" 
        color="primary" 
        sx={{ marginTop: 2 }}
        onClick={handleClick}
      >
        送信
      </Button>
    </Box>
  );
}

export default App;

これらの変更により:

  1. useApiフックは引数を取らなくなり、代わりにpost関数がnamemailを引数として受け取ります。
  2. Appコンポーネントでは、useApiを呼び出す際に引数を渡さず、handleClick関数内でpost関数を呼び出す際にnamemailの値を渡すようになりました。

この修正により、namemailの値はpost関数が呼び出されるときに渡されるようになり、より柔軟な実装になりました。

ここまでで、モックAPIを呼び出す簡単な入力フォーム画面が作成できました。

いろいろ送信してみたのでスクショを載せておきます。

AIが生成したコードは、上司とか先輩になったつもりでレビューする

いかがだったでしょうか?

今回は、AIに指示を出すときは前提を伝えることが大事、ということをシェアしました。
前提をしっかり伝えることができれば、生成したコードの質も上がっていくはずです。

しかし、たとえしっかりと指示が出せていたとしても、必ずしも完璧なコードが返ってくるとは限りません。

AIが生成したコードは、上司とか先輩になったつもりでレビューすることを忘れないようにしましょうね。

P.S.

TextFieldlabel 属性をプレースホルダだと勘違いしていて、「入力欄のヘッダーがないな」と思いTypography でヘッダーを作っていました。

      <Typography variant="h6" component="h2" align="left" sx={{ alignSelf: 'flex-start' }}>Name</Typography>
      <TextField
        label="田中 たろう"
        variant="outlined"
        fullWidth
        value={name}
        onChange={(e) => setName(e.target.value)}
      />

ですが、この label 属性はプレースホルダではなく、ヘッダーでしたね(^_^;)

ヘッダーがちょっとよくわからないことになっているので直しておきます。。。

あなたなら、Perplexityにどう指示を出しますか?

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

28歳のときに音楽家からエンジニアに転向。
WEB系のシステム開発(Java, C#, Vue, React など)に携わっています。

「できる」を増やしてワクワクな人生を送るための情報をシェアしています。

コメント

コメントする

目次