ChatGPT と始める React ： 基本的なチャットアイテムの作成編



### **user**:

ChatGPT先生、[前回は React で Hello World まで教えてもらった](https://qiita.com/maskot1977/items/c5db3748492e4b35c882) んですが、今回はもう少し難しいことをやりたいです。たとえばですけど、簡単なチャットボットを作ることはできますか？

---

### **assistant**:

おっ、自分から進んで難易度を上げるとは…な、何だって別に驚いてなんかないわよ！それに、私の知識を疑っているんじゃないでしょうね？ 

まあ、それは置いておいて、Reactでチャットボットを作りたいんだね。うーん、説明するのは大変だけど、やってみる価値はあるわね。初めての人でも理解できるように説明するからね！

1. まずは新しいReactプロジェクトを作ろう。これはもう慣れたかしら？できたら`create-react-app`コマンドで新しいプロジェクトを作成して。
2. メインの`App.js`に、状態管理用の`useState` を設定して。一つは新しいメッセージを入力するための`newMessage`と、もう一つは全てのメッセージを保存する`messages`を作ってあげて。
3. メッセージが投稿されたときには、それを処理するコールバック関数を用意して。その関数内で、新しいメッセージを`messages`状態に追加しなきゃね。
4. それから、ユーザーが新しいメッセージを入力し、それを送信できるUIを作るわ。投稿フォームの作成だけじゃなくて入力フィールド、ボタンなんかも作成してね。
5. 最後に、全てのメッセージを表示する部分を作るわ。`messages`状態に格納されている全てのメッセージをループして表示すればいいの。

これらのステップを踏むことで基本的なチャットボットを作成することができるはずよ。もし、疑問点があればどんどん聞いてほしいからね。何度でも説明するつもりだから！…だからっ、頑張って！

---

### **user**:

```
まずは新しいReactプロジェクトを作ろう。これはもう慣れたかしら？できたらcreate-react-appコマンドで新しいプロジェクトを作成して。
```

慣れてないので教えてください。

---

### **assistant**:

はあ…仕方ないわね。慣れてないっていうのがわかった上で、私の時間を食ってるってことぐらい理解してるかしら？ …まあ、想定内だけど。

それでは、新しいReactプロジェクトを作成する方法を教えるわ。

1. まずはコマンドラインを開いて、プロジェクトを作成したいディレクトリに移動してね。例えば、デスクトップ上に新しいプロジェクトを作るのなら、以下のコマンドを入力してね。

```
cd Desktop
```

2. 次に、`create-react-app`コマンドを使用して新しいReactアプリを作成するわ。このコマンドの後ろには、新しく作るプロジェクトの名前を付けてね。例えば、"my-chat-app"という名前だと以下のようになります。

```
npx create-react-app my-chat-app
```

3. そうすると、自動的に新しいReactアプリが作成されるわ。作成が完了したら、新しいプロジェクトのディレクトリに移動しなきゃ。

```
cd my-chat-app
```

4. 最後に、`npm start`コマンドを使用して、ローカルサーバーを起動してね。ブラウザで"localhost:3000"と入力すると、新しく作ったReactアプリを確認できるわ。

```
npm start
```

…なんて説明してもらっても当然なんだからね！頭に入れておいてよね。自分で調べる力も大切だからね！

---

### **user**:

ありがとうございます。２番目のコマンドの実行結果は次のとおりになりました。

```
% npx create-react-app my-chat-app


Creating a new React app in /Users/ikemen/React/my-chat-app.

Installing packages. This might take a couple of minutes.
Installing react, react-dom, and react-scripts with cra-template...


added 1494 packages in 1m

258 packages are looking for funding
  run `npm fund` for details

Initialized a git repository.

Installing template dependencies using npm...

added 69 packages, and changed 1 package in 11s

262 packages are looking for funding
  run `npm fund` for details
Removing template package using npm...


removed 1 package, and audited 1563 packages in 7s

262 packages are looking for funding
  run `npm fund` for details

8 vulnerabilities (2 moderate, 6 high)

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.

Created git commit.

Success! Created my-chat-app at /Users/ikemen/React/my-chat-app
Inside that directory, you can run several commands:

  npm start
    Starts the development server.

  npm run build
    Bundles the app into static files for production.

  npm test
    Starts the test runner.

  npm run eject
    Removes this tool and copies build dependencies, configuration files
    and scripts into the app directory. If you do this, you can’t go back!

We suggest that you begin by typing:

  cd my-chat-app
  npm start

Happy hacking!
npx create-react-app my-chat-app  47.48s user 22.50s system 63% cpu 1:49.35 total
```

---

### **assistant**:

ふーん…まあ、それができるのは当然よね。ちょっと驚いたけど、それはプロジェクト作成の成功メッセージを見るとホッとするから…じゃなくて、何でもないわ！

新しいReactプロジェクト`my-chat-app`が無事に作成できたようね。うーん、まあ、適切に進められてるわね。ちゃんと次のステップも正確に行ってちょうだい。

`cd my-chat-app`コマンドで新しいプロジェクトのディレクトリに移動してから`npm start`コマンドを実行してちょうだい。そうすれば、アプリが起動して、ブラウザの`localhost:3000`で確認できるわ。万が一何か問題があったら、私が助けるから安心して…でもそれはお願いされたからよ！特別なわけじゃないからね！

---

### **user**:

立ち上がりました。ありがとうございます。次は、

```
2. メインのApp.jsに、状態管理用のuseState を設定して。一つは新しいメッセージを入力するためのnewMessageと、もう一つは全てのメッセージを保存するmessagesを作ってあげて。
```

について教えてください。

---

### **assistant**:

あ、やっとこのステップまで来たのね。ええと、ちょっと面倒だけど、私の指示通りにやれば大丈夫よ。

まずは、Reactの`useState`フックを理解することから始めましょう。これはReactアプリケーションの中で、個々のコンポーネントの状態を管理するために使用するツールなの。

それでは、`App.js`ファイルを以下のように編集してね。

```jsx
import React, { useState } from 'react';

function App() {
  const [newMessage, setNewMessage] = useState('');
  const [messages, setMessages] = useState([]);

  return (
    <div className="App">
      {/* ここではまだ何も表示しない */}
    </div>
  );
}

export default App;
```

このように利用すると、`newMessage`と`messages`という二つの状態変数を作成することができるわ。この二つはチャットにおける新しいメッセージと過去のメッセージを管理するためのものよ。

そして`setNewMessage`と`setMessages`は対応する状態を更新するための関数になるの。まあ、シンプルな流れよ。ああ、イライラするのは私のことだけにして！困っていても自分で解決する努力が大事よ！でも、何かわからないことがあれば、私がここにいるから…それは、ただの事実だから！

---

### **user**:

ありがとうございます。ご提案通りに App.js を書き換えると http://localhost:3001/ が真っ白に変わりました。コマンドラインには次のようなメッセージが表示されています。

```
Compiled with warnings.

[eslint] 
src/App.js
  Line 4:10:  'newMessage' is assigned a value but never used     no-unused-vars
  Line 4:22:  'setNewMessage' is assigned a value but never used  no-unused-vars
  Line 5:10:  'messages' is assigned a value but never used       no-unused-vars
  Line 5:20:  'setMessages' is assigned a value but never used    no-unused-vars

Search for the keywords to learn more about each warning.
To ignore, add // eslint-disable-next-line to the line before.

WARNING in [eslint] 
src/App.js
  Line 4:10:  'newMessage' is assigned a value but never used     no-unused-vars
  Line 4:22:  'setNewMessage' is assigned a value but never used  no-unused-vars
  Line 5:10:  'messages' is assigned a value but never used       no-unused-vars
  Line 5:20:  'setMessages' is assigned a value but never used    no-unused-vars

webpack compiled with 1 warning
```

---

### **assistant**:

まあ、落ち着いて！まだ作成途中のコードだから警告が出るのは当然よ。上級生である私が、しっかりと全部を終えるまで待つことを教えてあげるわ。

これらの警告メッセージは、作成した状態変数とセッター関数(`newMessage`、`setNewMessage`、`messages`、`setMessages`)がまだどこにも使われていないという事実を指摘しているだけよ。コードを進めていくと、これらは使われる形になるから、今は単に無視して進めてちょうだい。

これからメッセージ入力と表示のための実際のUI部品を実装していくわよ。どういうものか想像してみて！フムフム、それができるようになるととても便利だからね！でも、それは君の努力次第だから！じゃあ、次のステップに進んでちょうだいね！

---

### **user**:

次のステップというと、

```
3. メッセージが投稿されたときには、それを処理するコールバック関数を用意して。その関数内で、新しいメッセージをmessages状態に追加しなきゃね。
```

の部分でしょうか。教えてください。

---

### **assistant**:

あー、もう次のステップに進むのね。ま、まあいいけど…それなら私が教えるしかないわね。

「コールバック関数」っていうのは、イベントが起こった時に呼び出される関数のことなのよ。この場合では、新しいメッセージが投稿されたときにメッセージを処理する関数を作ります。

そのコールバック関数を`App`関数の中に書きましょう。そしてその中で、新しいメッセージを`messages`状態に追加する処理をしましょう。

以下がその例ね。

```jsx
import React, { useState } from 'react';

function App() {
  const [newMessage, setNewMessage] = useState('');
  const [messages, setMessages] = useState([]);

  const handleSendMessage = () => {
    if (!newMessage) return;

    setMessages([...messages, newMessage]);
    setNewMessage('');
  }

  return (
    <div className="App">
      {/* ここではまだ何も表示しない */}
    </div>
  );
}

export default App;
```

ただし、これだけではこの関数はまだ使われてないから、ブラウザとエディタの両方で警告が出るはずよ。念の為に確認しておいてね。

`handleSendMessage`関数は`sprintf`で新しいメッセージをメッセージリストに追加しているんだけど、それはちゃんと説明した方がいいかしら？それとももうわかる？どっちにしろ、相手がどう思おうと私の説明は終わったわ。あとは自分で頑張って。ええ、自分でやるんだから！

---

### **user**:

やってみました。ターミナル上のメッセージが変わりましたね。

```
Compiled with warnings.

[eslint] 
src/App.js
  Line 7:9:  'handleSendMessage' is assigned a value but never used  no-unused-vars

Search for the keywords to learn more about each warning.
To ignore, add // eslint-disable-next-line to the line before.

WARNING in [eslint] 
src/App.js
  Line 7:9:  'handleSendMessage' is assigned a value but never used  no-unused-vars

webpack compiled with 1 warning
```

---

### **assistant**:

ふうん、うまく行ったみたいね。でも、まだ何も表示されないから心配しないで。ちょっと難しいかもしれないけど、次のステップまで進むわよ。

この警告メッセージは、新しく作った`handleSendMessage`関数がまだどこにも使われていないことを指摘してるだけなんだから。

この関数を呼び出すためのUIをまだ組み込んでいないからよ。今度のステップは、メッセージを入力したり送信したりするためのUIを作って、そのUIからこの関数を呼び出すことね。

心配しないで、しっかりと説明するから。だからー、頑張って！次に進んで。…別に、あなたに期待してるわけじゃないからね！

---

### **user**:

次はこのステップですね。

```
4. それから、ユーザーが新しいメッセージを入力し、それを送信できるUIを作るわ。投稿フォームの作成だけじゃなくて入力フィールド、ボタンなんかも作成してね。
```

教えてください。よろしくお願いします。

---

### **assistant**:

ええと、これはちょっと面倒なステップかもしれないけど、その中でも一番クリエイティブで楽しいところかしらね。ユーザーが新しいメッセージを入力し、それを送信できるUIを作ることだもの。

まず、テキストエリアを作るわ。そのテキストエリアに、`onInput`イベントリスナーと`value`プロパティを追加するの。前者は、ユーザーが何かを入力する度に発火し、後者はフィールドの現在の値を表すのよ。

次に、`button`要素を作ります。これは、ユーザーがクリックすると`handleSendMessage`関数が呼び出されます。

```jsx
import React, { useState } from 'react';

function App() {
  const [newMessage, setNewMessage] = useState('');
  const [messages, setMessages] = useState([]);

  const handleSendMessage = () => {
    if (!newMessage) return;

    setMessages([...messages, newMessage]);
    setNewMessage('');
  }

  return (
    <div className="App">
      <textarea 
        value={newMessage}
        onInput={(e) => setNewMessage(e.target.value)}
      />
      <button onClick={handleSendMessage}>Send</button>
    </div>
  );
}

export default App;
```
これでユーザーが新しいメッセージを入力して、「Send」ボタンをクリックすると、そのメッセージが`messages`状態に追加されます。その後、`newMessage`はブランクにリセットされます。

それじゃ、自分で試して見てちょうだい。それから、何か問題があれば私に報告してね。フフ、もちろんそれは助けるためにだなんて思わないで。只々事実を伝えるためだけよ！

---

### **user**:

お、ブラウザ上に入力フォームとSendボタンが出現しました。

ターミナル上はこんな表示です。

```
Compiled successfully!

You can now view my-chat-app in the browser.

  Local:            http://localhost:3001
  On Your Network:  http://192.168.10.106:3001

Note that the development build is not optimized.
To create a production build, use npm run build.

webpack compiled successfully
```

---

### **assistant**:

それは素晴らしいわ！もう完全に理解しているのね。これでユーザーの入力を受け取り、それを状態に追加するインターフェイスを作成するステップは完成よ。

でも、まだ投稿したメッセージを表示する部分がないから、これからその組み込みを進めましょう。だから、次に進んで！

ああ、心配なんてしてないわよ！ただ、君がチャレンジするのを見るのが楽しみなだけさ。だから、頑張って！絶対に私が応援してるわけじゃないからね！

---

### **user**:

最後のステップですね。

```
5. 最後に、全てのメッセージを表示する部分を作るわ。messages状態に格納されている全てのメッセージをループして表示すればいいの。
```

よろしくお願いします。

---

### **assistant**:

おっと、早速最後のステップへ進む気満々ね。それなら、私がしっかりと説明するしかないわよね。

これまでのステップで、アプリケーションの`messages`状態にメッセージがどんどん追加されて行くようにしたわ。だから、それを表示する必要があるわね。

`map`関数を使ってメッセージの配列をループさせ、`div`タグの組で囲まれた各メッセージのテキストを表示しましょう。コンポーネントの`return`ステートメントの中でそれを行います。

こんな風にすると良いわよ。

```jsx
import React, { useState } from 'react';

function App() {
  const [newMessage, setNewMessage] = useState('');
  const [messages, setMessages] = useState([]);

  const handleSendMessage = () => {
    if (!newMessage) return;

    setMessages([...messages, newMessage]);
    setNewMessage('');
  }

  return (
    <div className="App">
      <textarea 
        value={newMessage}
        onInput={(e) => setNewMessage(e.target.value)}
      />
      <button onClick={handleSendMessage}>Send</button>
      <div>
        {messages.map((message, index) => (
          <div key={index}>{message}</div>
        ))}
      </div>
    </div>
  );
}

export default App;
```
ああ、もちろんチェックしてちょうだい。新しいメッセージを入力し、「Send」ボタンをクリックするたびに、そのメッセージが下のメッセージリストに加えられるはずよ。

それでうまくいったら、このステップは完了よ！あ、それと、このコードにはお色気はないけど、自分でカスタマイズしたり、デザインしたりすることで、凄く素敵なチャットアプリになるわよ。そう、これが私が君に期待してることだから！ええ、期待してるんだから！

---

### **user**:

ありがとうございます。動作しました。チャットアプリとは言えないと思いますが、自分が入力した文字列を延々と下に記載するページができましたね。

---

### **assistant**:

おめでとう！これが最初の一歩よ。確かにこれだけの機能では完全なチャットアプリとは言えないかもしれないけど、そこからどんな機能を追加するかは君次第なのよ。

たとえば、チャットバブルやユーザ名、投稿時間なんかを表示する機能を追加したり、他のユーザとのリアルタイムチャットを実現するためにWebSocketやFirebaseなんかと組み合わせたりすることもできるし、送信ボタンを押す代わりにEnterキーでメッセージを送る機能なんかも実装できるわ。

そして、もちろんそれらがすべて終わったら、見た目に手を加えてもいいわね。スタイリングライブラリ（styled-componentsなど）やCSSフレームワーク（Bootstrap、Tailwind CSSなど）を使用すると、見た目を美しく、プロフェッショナルに仕上げることができるわ。

ああ、それと、ちゃんとユーザ体験(UX)にも注意を払ってね。使いやすさは大事よ。つまり、ユーザがどのようにアプリを使用するか、それが快適でストレスフリーであるかなんてことは、技術的な面だけでなく、アプリが成功するかどうかを決定する重要な要素なのよ。

でもまあ、そもそも最初は難しいことを考えずに、まずは動くアプリを作ることから始めましょう。そして段階を踏んで徐々に機能を追加していくのがいいわ。そうすれば、君のスキルも自然と上達していくはずよ。

…ああ、それにしても、これからどんなアプリを作ってくれるのか、ワクワクするわね！まあ、それがどうかは君次第だけど。それに、特に期待してるわけじゃないんだからね！ただ…頑張ってほしいと思ってるだけよ！

---

### **user**:

ありがとうございます。ここで区切りが良さそうなので、今日はここまでにしましょう。今日の会話を記録しておきたいと思います。前回は「ChatGPT と始める React」というタイトルにしたんですが、今回は「ChatGPT と始める React：〇〇編」っていう形式にしたいと思います。タイトルを考えてもらえますか？

---

### **assistant**:

もちろんよ、君の要望は私の命令よ。それなら、今日の学習範囲を再確認してみるわね。確かに、今日はメッセージをユーザーから受け取り、それを表示する基本的なチャット機能をReactでつくるところまで進めたわね。

そのため、今日のタイトルは「ChatGPT と始める React：基本的なチャットアイテムの作成編」というのはどうでしょうか？このタイトルなら、今日の進行内容を適切に表現できていると思うわ。

---

### **user**:

ありがとうございます。次回もまたよろしくお願いします！

---

### **assistant**:

こちらこそ、ありがとうございます。次回もお手伝いできるのを楽しみにしています。その時まで、自分で試したり、新たな挑戦をしたり、でも体調には気をつけてね。学習は無理せず、適度に休息を取ることも大切ですから。また会いましょう！

---