React Hookを使ってチャットボットを作成した

# 概要
React初心者です。
少し前にReactのHookを使って簡単なチャットボットを作成しました。
若干ウザめなチャットボットですが、恥を忍んで記事にさせていただきます。

#完成したチャットボット
某元テニスプレイヤーの方が熱い言葉で返してくれるチャットボットです。
![ezgif.com-gif-maker (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578913/f42aefbb-e6f6-3b2a-65d0-fdc90d88c499.gif)



# 開発環境
React Hookの学習がメインだったので、UIやサーバ側は既存のサービスに頼りました。

- `React 16.13.1`
- `Material UI`　
- `Firebase（Firestore、 Functions、Hosting）`

#ファイル構造
```
src
├── assets
│   ├── image              
│   └── styles　　　　　　　　
├── components
│   ├── Answer.jsx
│   ├── AnswersList.jsx
│   ├── Chat.jsx
│   ├── Chats.jsx
│   └── index.js　　　　　  //components内のjsxファイルをまとめたもの
├── App.jsx　　　　　
├── dataset.json　　　　　  //firestoreへアップするデータ
├── firebase
├── index.js
└── serviceWorker.js
```

#componentsの中身について
以下の4つに分類しています。
![スクリーンショット 2020-12-05 22.56.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578913/bcef3585-fb18-e33c-7e60-332e9e4a9268.png)




index.jsにはcomponentsで作成したjsxファイルをまとめてexportしておきます。

```components/index.js
export {default as AnswersList} from './AnswersList';
export {default as Answer} from './Answer';
export {default as Chats} from './Chats';
export {default as Chat} from './Chat';
```

これにより、一行で複数のcomponentをimportして使えます。

```App.jsx
import { AnswersList, Chats } from './components/index';
```


#データベースについて
Firebaseの「<a href="https://firebase.google.com/docs/firestore?hl=ja">`Firestore`</a>」を使いました。

まず、保存したいデータをjson形式で作成します。

```dataset.json
{
  "init": {
    "answers": [
        {"content": "仕事で悩んでいます", "nextId": "work"},
        {"content": "恋愛に悩んでいます", "nextId": "love"},
        {"content": "人生に悩んでいます", "nextId": "life"},
        {"content": "ただ元気がありません", "nextId": "health"}
    ],
    "question": "おい、そこの君！いつもの笑顔がないぞ！"
},
"work": {
  "answers": [
      {"content": "上司に叱られました", "nextId": "work_1"},
      {"content": "ミスをしました", "nextId": "work_2"},
      {"content": "イライラすることがありました", "nextId": "work_3"},
      {"content": "疲れました", "nextId": "work_4"},
      {"content": "辞めたいです", "nextId": "work_5"}
  ],
  "question": "仕事で何があったんだ？"
},
//以下省略
```

「answers」　：ユーザー側の回答
「content」　  ：ユーザーの回答選択肢
「nextId」　　：回答選択後の遷移先キー
「question」　：某Mさんからの自動回答

最初は「init」の内容が表示され、その後は選択された内容に応じて次の内容(nextId)が呼び出されるようになっています。

# 使用したHook
`useState`、`useEffect`、`useCallback`を使いました。
それぞれの役割については<a href="https://ja.reactjs.org/docs/hooks-overview.html">こちら</a>をご参考ください。

##useState
チャット内容、回答選択肢が変更されると、それらを状態として保持し管理します。

```.jsx
const [answers, setAnswers] = useState([]),
      [chats, setChats] = useState([]);
```

##useEffect
最新のチャット内容がチャット下部に常に表示されるようにしたいので、
追加される(scrollAreaの値が変化する)と自動スクロールするようにしています。

```jsx
  useEffect(() => {
    const scrollArea = document.getElementById('chats-area')
    if(scrollArea) {
      scrollArea.scrollTop = scrollArea.scrollHeight
    }
  })
```


##useCallback
初期の回答選択肢を保持し、ユーザーが回答を選択すると、チャット内容を変更＆次の回答選択肢を準備する動きをしています。

また、`setTimeout`を使い、ボットっぽく敢えてタイムラグが発生するような動きにしています。

```.jsx
  const selectAnswer = useCallback((selectedAnswer, nextQuestionId) => {
    addChats({
      text: selectedAnswer,
      type: 'answer'
    })
    setTimeout(() => displayNextQuestion(nextQuestionId, dataset[nextQuestionId]), 1000);
  },[answers])

```

#最後に
今回はチャットボットを作ってみましたが、Hookの簡単な動きは理解できたかなと思います。
ページ構造が簡易的すぎて少し物足りなさもありますが…
他にも個人開発向けでHookをふんだんに使えそうなものがあればぜひ教えていただけると嬉しいです。挑戦してみたいと思います。

チャットボットはこちらの<a href="https://www.youtube.com/user/1492tiger">Youtubeのサイト</a>を参考にさせていただきました。
解説が非常にわかりやすいので、特に初心者の方におすすめです。