こんにちは。
今日はベビーの一ヶ月検診でした。
私は産院に入れないので入口まで見届けて、スタバでカタカタしていました。
さて、前回までの記事では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;
インストールスクリプトだけじゃなく、サンプル画面も作ってくれましたね。
気が利くー
では、提案されたコードを使って、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;
この更新されたコードでは以下の変更を行いました:
useApi
フックを作成し、name
とpost
関数を返すようにしました。- Appコンポーネント内で
name
と- 各
TextField
コンポーネントにvalue
とonChange
プロパティを追加し、state値の表示と更新を行えるようにしました。handleClick
関数を作成し、送信ボタンがクリックされたときにuseApi
フックから返されたpost
関数を呼び出すようにしました。- 送信ボタンに
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;
これらの変更により:
useApi
フックは引数を取らなくなり、代わりにpost
関数がname
とApp
コンポーネントでは、useApi
を呼び出す際に引数を渡さず、handleClick
関数内でpost
関数を呼び出す際にname
とこの修正により、
name
とpost
関数が呼び出されるときに渡されるようになり、より柔軟な実装になりました。
ここまでで、モックAPIを呼び出す簡単な入力フォーム画面が作成できました。
いろいろ送信してみたのでスクショを載せておきます。

AIが生成したコードは、上司とか先輩になったつもりでレビューする
いかがだったでしょうか?
今回は、AIに指示を出すときは前提を伝えることが大事、ということをシェアしました。
前提をしっかり伝えることができれば、生成したコードの質も上がっていくはずです。
しかし、たとえしっかりと指示が出せていたとしても、必ずしも完璧なコードが返ってくるとは限りません。
AIが生成したコードは、上司とか先輩になったつもりでレビューすることを忘れないようにしましょうね。
P.S.
TextField
の label
属性をプレースホルダだと勘違いしていて、「入力欄のヘッダーがないな」と思い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にどう指示を出しますか?

コメント