Reactとフックを使ったチャットウィンドウの作成
Published: 2024-03-07 07:34:58

**読み進める前に**...アーカイブからのこの記事は私たちのPubNub React SDKを使用していますが、新しいChatアプリケーションはTypeScriptで書かれた専用の[Chat SDKと](https://www.pubnub.com/docs/chat/chat-sdk/overview)フックを使用する付属の[サンプルアプリを](https://www.pubnub.com/docs/chat/chat-sdk/build/sample-chat)使用する必要があります。

[チャットは](https://pubnub.com/solutions/chat/) ほとんどのインタラクティブなアプリケーションの重要な部分 です。 [ヘルスケアアプリから](https://pubnub.com/solutions/digital-health/) [グループチャット](https://www.pubnub.com/solutions/multiuser-collaboration/)、チャットボットまで、リアルタイムのコミュニケーションはあらゆるマルチユーザーアプリに期待されています。最初から適切なフレームワークとインフラストラクチャを選択すれば、この機能の統合はよりシームレスになります。このチュートリアルでは 、[React](https://reactjs.org/)、 [Material-UI](https://material-ui.com/)、 [PubNubを使って](https://www.pubnub.com/) チャットウィンドウを作成 する方法を紹介します。

私たちのアプリは、誰でも好きなチャンネルでリアルタイムに接続してチャットできるようにします。ReactフレームワークとMaterial-UIコンポーネントを使用して、このチャットをゼロから作成します。メッセージの送受信にはPubNub APIを使います。これら3つのピースによって、モダンで高速なチャットを作成することができます。

また、このチュートリアルでは 、冗長なコードを減らし、関連する部分を整理するReactコンポーネントの新しい書き方である[Hooksを](https://reactjs.org/docs/hooks-intro.html)利用 します。なぜ、そしてどのようにこれらの新機能を使うかについては、チュートリアルの後半で詳しく説明します。このチュートリアルが終わったら、チャンネル名を持っている人なら誰でも会話できるチャットを用意します。チャンネルはURLとページで表現されるので、チャンネルを共有するのは簡単です！

[![react hooks chat](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1jkx/cadaa09d1dbce7a6f13e1fce08cc4a30/react-hooks-chat.gif)](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1jkx/cadaa09d1dbce7a6f13e1fce08cc4a30/react-hooks-chat.gif)

Pub/Subと履歴の取得
-------------

PubNubはメッセージを送信するためのシンプルで高速なインフラストラクチャを提供します。PubNubは、世界中の事実上無制限の人々やシステムを1/4秒以下で接続するために使用されます。 PubNubは数多くのSDKが 用意されており、[チャットに特化したリソースセンターも](https://www.pubnub.com/developers/chat-resource-center/)用意されています。このアプリの作成では、リアルタイムのメッセージングにPublish/Subscribeを使用し、メッセージを保持するためにStorage & Playbackを使用します。

**Publishは**、特定のチャンネルで聞いている人にメッセージを送信する手段を提供します。 [ReactでPublish](https://www.pubnub.com/docs/sdks/react#publish-and-subscribe)する方法を 学びましょう。

**Subscribeは**PubNubに特定のチャンネルに送信されるメッセージを受け取りたいことを伝える手段です。 Reactで[Subscribe](https://www.pubnub.com/docs/sdks/react#publish-and-subscribe)する方法はこちら 。

**Storage&Playbackとは**、あるチャンネルのメッセージを受信するために、その時点で誰かが購読している必要はないということです。ユーザが接続したときに、直近のメッセージを取得して表示することができます！ React[でメッセージを保存 &](https://www.pubnub.com/docs/react-native-javascript/api-reference-storage-and-playback)再生する方法については 、こちらをご覧ください。

はじめに
----

このチャットの例では、1つのAPIを利用するだけで、すべてのチャット機能を利用できます。以下のフォームを使用してPubNubアカウントを作成するか、すでにアカウントを持っている場合はログインする必要があります。

まず 、[管理者ダッシュボードで](https://admin.pubnub.com/)固有のpub/subキーを取得 し、キーオプションページの左下にあるStorageとPlaybackを有効にします。私はメッセージの保存期間を1日に設定しましたが、ご自分に最適な期間を選択してください。変更は必ず保存してください。

これでセットアップが完了したので、Reactプロジェクトのセットアップを開始できる。

### React.jsとPubNubのインストール方法

React.jsとPubNubをインストールするには、まずNode.jsとnpmがあることを確認する必要がある。 Node[.jsの公式ホームページから](https://nodejs.org/en/)インストールして ください。すでにインストールされている場合は、npmのバージョンが5.2以上であることを確認してください。

```js
npm -v
```

をターミナルに入力して、npmのバージョンが5.2以上であることを確認してください。これで、Reactアプリを作成し、PubNub SDKをインストールするためのパッケージマネージャが揃いました。

Node.jsをインストールしたら、これらのコマンドを実行してプロジェクトを作成し、必要なモジュールをインストールします。Reactがあなたのウェブサイトを構築するのを待ちます！それが完了したら、2行目でPubNubをインストールします。3行目はスタイリングフレームワークのMaterial-UIをインストールします。

```js
npx create-react-app <your-app-name>
cd <your-app-name>
npm install --save pubnub
npm install @material-ui/core
```

これでコーディングを始めるのに必要なものはすべて揃った！ターミナルに

```js
npm start
```

を入力し、実行が完了したら表示されるリンクをクリックすると、空のreactページが表示されるはずです！さっそくコーディングしてみよう！

なぜReact Hooksを使うのか？
-------------------

2018年10月以前は 、[ローカル変数を保存するためにクラスコンポーネントを](https://reactjs.org/docs/state-and-lifecycle.html#adding-local-state-to-a-class)使用する必要が ありました。Hooksは、機能コンポーネントの内部に状態を保存する機能をもたらし、Hooksはクラスに付随する肥大化の多くを取り除きました。

Hooksは大規模アプリケーションの開発を容易にし、その機能は類似したコードをグループ化するのに役立つ。コンポーネント内のロジックは、何を するのか 、いつする必要があるのかによって整理さ れる。componentDidMountやcomponentDidUpdateの ような通常のライフサイクル関数は使用せず、代わりにuseEffectを 使用する。

useEffectは、私たちが使う2つの主要なフックのうちの1つで、もう1つはuseStateだ。useStateは新しいsetStateだが、動作は少し異なる。 [React Hooksのドキュメントでは](https://reactjs.org/docs/hooks-intro.html)、 さらにいくつかのフックについて詳しく説明されているが、フックのもうひとつの優れた点は、自分自身で作成できる ことだ！ すでにあるものを利用することで、時間とコードの行数を節約できます。

このチュートリアルでは、useEffect、useStateの使い方と、独自のフックの作り方を紹介します！

カスタムReactフックの作成
---------------

まずは、今後のコードを簡略化するための独自のフックを作成するところから始めましょう。それぞれの入力に対して個別にonChange関数を作成する代わりに、それぞれの入力に対して今できることを1つのHookにまとめましょう！

作成したプロジェクト・フォルダーの中を見ると、いくつかの異なるフォルダーがあるのがわかる。src "フォルダに移動して、そこに "useInput.js "という新しいファイルを作成します。フックのルールでは、すべてのフックは "use "で始まらなければならない。また、フックはトップ・レベルでのみ使用されるべきものであり、関数や条件、ループの中で使用することはできない。また、通常のJS関数からフックを呼び出すことはできず、Reactの関数コンポーネントとカスタムフックのみとなります！フックの背後にある一般的なルールがわかったところで、フックを作ってみましょう！

このフックでは、useStateフックを使います。ファイルの一番上にある'react'からuseStateをインポートし、'useInput'という名前の関数を作成します。

```js
import { useState } from 'react';
function useInput()
{
  //Define our Hook
}
```

ここで構文が少し面白くなる。デストラクチャリング代入を使えば、useStateが与えてくれる2つのオブジェクトを、たった1行のコードで受け取ることができる。しかし、useStateは何を返してくれるのだろうか？基本的には、ゲッターとセッター、値を格納する変数、それを設定する関数を返してくれる！でステートにアクセスする代わりに

```js
this.state.xxxxx
```

でアクセスする代わりに、名前だけでアクセスすることができます。

```js
let [value, setValue] = useState('');
```

onChangeという名前の新しい変数に代入する関数式を作成する。関数に "event "を渡し、その内部でステートの値をイベントのターゲットの値に設定する。value」、「setValue」、「onChange」という3つの変数／関数を作成したら、それを返そう。

```js
let onChange = function(event){
  setValue(event.target.value);
};
return {
  value,
  setValue,
  onChange
};
```

最後に

```js
export default useInput;
```

をファイルの最後に追加して、メインのアプリで使えるようにする！

Reactコンポーネントをデザインする
-------------------

これでHookが完成しました。App.jsファイルをセットアップしよう！ファイルの一番上にインポートする重要なファイルがいくつかあります：Reactと必要な2つのデフォルトのHook、先ほど作ったuseInputフック、App.cssファイル、PubNub、そしてMaterial-UIコンポーネントだ。

App.cssの中身を以下のように置き換える。

```js
* {
  margin: 0;
  padding: 0;
}
body {
  width: 500px;
  margin: 30px auto;
  background-color: #fff;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
    "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
    sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
    monospace;
}
.top {
    display: flex;
    flex-direction: row;
    justify-content: space-between;
}
```

機能コンポーネントのヘッダーを使ってチャットのアウトラインを作ってみよう。これはチャットにどのようなデザインとフローを求めるかを考えるのに役立ちます。私は3つの異なるコンポーネントを選択しました：App、Log、Message です。

App には、ログ、入力、送信ボタンがあります。Log はメッセージのリストを保持し、Message はメッセージと送信者を表示します。ファイルの最初に必要なモジュールをインポートしてください！

```js
//These are the two hooks we use the most of through this Chat
import React, { useState, useEffect} from 'react';
//has a few css stylings that we need.
import './App.css';
//This is a hook we created to reduce some of the bloat we get with watching inputs for changes.
import useInput from './useInput.js';
//Lets us import PubNub for our chat infrastructure capabailites.
import PubNub from 'pubnub';
//Material UI Components
import {Card, CardActions, CardContent,List, ListItem,Button,Typography,Input} from '@material-ui/core';
// Our main Component, the parent to all the others, the one to rule them all.
function App(){
  //Bunch of functions!
  //return()
}
//Log functional component that contains the list of messages
function Log(props){
  //return()
}
//Our message functional component that formats each message.
function Message(props){
  //return()
}
```

これらの各コンポーネントにはリターン関数があり、各コンポーネントがどのように見えるかを設計することができます。どのような情報を親から子へと受け継がせるかを決めることができるのです。この設計によって、各コンポーネントが機能するのに必要なものだけを与え、情報を下方に渡すことができる。

アプリ・コンポーネントのセットアップReact Hooksを使ったステート
-------------------------------------

AppはメインのReactチャット・コンポーネントです。このコンポーネントでは、チャンネルに変更がないかURLをチェックしたり、ステートをセットアップしたり、それからAppに何をさせたいか、そしてそれがいつ起こるかを選別するためにいくつかのuseEffect関数を作るなど、セットアップしなければならないことがいくつかあります。

App内部での最初のアクションは、デフォルトのチャンネルを作成することだ。"Global "がいいだろう。次に、チャンネルがないかURLをチェックする。ない場合はデフォルトのままでいいが、ある場合はデフォルトのチャンネルを設定する。

```js
let defaultChannel = "Global";
//Access the parameters provided in the URL
let query = window.location.search.substring(1);
let params = query.split("&");
for(let i = 0; i < params.length;i++){
  var pair = params[i].split("=");
  //If the user input a channel then the default channel is now set
  //If not, we still navigate to the default channel.
  if(pair[0] === "channel" && pair[1] !== ""){
    defaultChannel = pair[1];
  }
}
```

ステートを初期値とともに定義しよう。useStateを使ってチャネルのゲッターとセッターを取得し、デフォルトのチャネルを初期値として設定します。メッセージの配列も同様に、初期値は空の配列にします。

また、現在の時刻に基づいて、一般的なユーザ名を設定します。次に、作成した新しいフックに一時的なチャネルとメッセージ変数を設定します。これで、アプリのステートが設定された。

```js
const [channel,setChannel] = useState(defaultChannel);
const [messages,setMessages] = useState([]);
const [username,] = useState(['user', new Date().getTime()].join('-'));
const tempChannel = useInput();
const tempMessage = useInput();
```

ReactのuseEffect
---------------

次に、みんなが話題にしている新しいuseEffectを使ってみよう。これは基本的に、フックを使っていないときの古いライフサイクル・メソッドをすべて置き換えて再編成したものだ。各関数は、2番目のパラメータとして変数の配列を指定しない限り、再レンダリングのたびに実行されます。これらの変数が変更されるたびに、useEffectが再実行されます。

_覚えておいてほしいのは、これはSHALLOW等値チェックであるということです。数値や文字列は、別のものとして設定するたびに異なるものとしてカウントされますが、useEffectはオブジェクトのポインタを見るだけで、属性を見るわけではありません。_

useEffectはオブジェクトのポインタを見るだけで、属性を見るわけではありません。基本的に、それぞれのuseEffectは、それが変更するために依存しているものによってグループ化され、したがって、同様の依存関係を持つアクションが一緒に実行されます。

```js
useEffect(()=>{
  //Put code we want to run every time these next variables/states change
},[channel, username]);
```

ReactでPubNubをセットアップする
---------------------

この新しいHookがどのように機能するかがわかったので、次のステップは新しいPubNubオブジェクトを作成することだ！PubNubを立ち上げて、先ほど生成したPublishキーとSubscribeキーを取得し、新しいオブジェクトに配置します。また 、 この接続に [UUIDを設定](https://www.pubnub.com/docs/react-native-javascript/api-reference-configuration#uuid)することができます 。IPであれ、ユーザー名であれ、 [生成されたUUID](https://www.pubnub.com/docs/react-native-javascript/api-reference-configuration#generate-uuid-arg)であれ、ユースケースが定義するユニークな識別子であれ、何でもかまいません。私は簡単のためにユーザー名として設定した。

```js
const pubnub = new PubNub({
  publishKey: "<ENTER-PUB-KEY-HERE>",
  subscribeKey: "<ENTER-SUB-KEY-HERE>",
  uuid: username
});
```

オブジェクトに接続 情報を入力したら、[PubNubイベントのリスナーを](https://www.pubnub.com/docs/web-javascript/api-reference-publish-and-subscribe#listeners)追加しましょう！これは新しいメッセージや新しい接続、ステータスを検出したり、プレゼンスイベントを処理したりするのに便利です。私たちのアプリはプレゼンスイベントを使用しませんし、ステータスリスナーを作成する必要もありません。私たちのアプリに本当に必要なのは、入ってくるメッセージを受信して処理する機能なので、それを定義しよう！

メッセージ・テキストがnullか空かをチェックし、nullでなければnewMessageオブジェクトを生成する。メッセージの配列に、受信した新しいメッセージを連結した現在の状態をセットします。arrow関数は、初期レンダリングの状態ではなく、現在のメッセージの状態を使用していることを確認します。

```js
pubnub.addListener({
  status: function(statusEvent) {
    if (statusEvent.category === "PNConnectedCategory") {
      console.log("Connected to PubNub!")
    }
  },
  message: function(msg) {
    if(msg.message.text){
      let newMessages = [];
      newMessages.push({
        uuid:msg.message.uuid,
        text: msg.message.text
      });
      setMessages(messages=>messages.concat(newMessages))
    }
  }
});
```

この状態でチャネルに登録すると、PubNubサーバへの最初の接続になります！Presenceがユースケースにとって重要な場合は、ここで有効にします。 [PubNub React SDKのPresenceで](https://www.pubnub.com/docs/react-native-javascript/api-reference-presence)チャンネルに誰が いるかを確認します。

```js
pubnub.subscribe({
  channels: [channel]
});
```

履歴を組み込むことはチャットの重要な機能なので、いくつかのメッセージを引き出してチャットログを形成してみましょう。最初にチャネルに接続したら、履歴関数を使用して保存されているメッセージを取得します。レスポンスを使用して古いメッセージにアクセスし、一時的な配列に格納します。配列は空であるべきなので、古いメッセージを空のメッセージ配列にプッシュすることができます。

```js
pubnub.history({
      channel: channel,
      count: 10, // 100 is the default
      stringifiedTimeToken: true // false is the default
}, function (status, response){
  let newMessages = [];
  for (let i  = 0; i < response.messages.length;i++){
    newMessages.push({
      uuid:response.messages[i].entry.uuid ,
      text: response.messages[i].entry.text
    });
  }
  setMessages(messages=>messages.concat(newMessages))
});
```

useEffectのもうひとつのすごいところは、再実行する前にすべてをシャットダウンする動作を定義できることだ！関数 "cleanup "を返し、その内部で[すべてのチャンネルからの登録を](https://pubnub.com/developers/chat-resource-center/docs/reference/connecting#disconnecting-from-pubnub)解除し、メッセージを別の空の配列にセットしてみよう。

```js
return function cleanup(){
  pubnub.unsubscribeAll();
  setMessages([]);
}
```

Pub/Sub: パブリッシング
----------------

チャンネルを購読しましたが、まだ発行していません。先ほどのuseEffectのPubNubの機能とは異なり、ユーザがメッセージを送信したときに公開したい。チャンネルにメッセージを公開するpublishMessageという名前の関数を作ってみましょう。

関数を作成し、そこに一時的なメッセージがあるかどうかを確認します。もしあれば、メッセージオブジェクトを作成します！メッセージとユーザ名の両方を含めることで、どのデバイスからメッセージにアクセスしても誰が送信したかがわかるようにした。まず、前回と全く同じPubNubオブジェクトを作成します。新しいメッセージとチャンネルを引数にしてpublishを呼び出す。

メッセージを送信した後、一時的なメッセージの状態をクリアします。これにより、ユーザは別のメッセージを送信することができます。この関数を呼び出すコードはまだどこにもないので、この関数は実行されませんが、次に定義する関数は実行されます！

```js
function publishMessage(){
  if (tempMessage.value) {
    let messageObject = {
      text: tempMessage.value,
      uuid: username
    };
    const pubnub = new PubNub({
      publishKey: "<ENTER-PUB-KEY-HERE>",
      subscribeKey: "<ENTER-SUB-KEY-HERE>",
      uuid: username
    });
    pubnub.publish({
      message: messageObject,
      channel: channel
    });
    tempMessage.setValue('');
  }
}
```

Reactイベントハンドラの作成
----------------

チャットで流動的なユーザーインタラクションを作成することは重要です。ユーザーがメッセージを送信するか、'Enter' キーでチャンネルを変更するためのハンドラを作成しましょう。イベントオブジェクトを受け取る handleKeyDown という関数を作成します。

```js
function handleKeyDown(event){
  //Handling key down event
}
```

この関数の中に入ったら、何がこのイベントのトリガーになっているのかを把握することが目的だ。後でインプットを作成するときにIDを設定する。まず、イベントのターゲットのIDをチェックする。もしそれが "messageInput "なら、押されたキーが'Enter'かどうかをチェックする。もしEnterキーだったら、publishMessage関数を呼び出す。

```js
if(event.target.id === "messageInput"){
  if (event.key === 'Enter') {
    publishMessage();
  }
}
```

このelse if文の最初にも先ほどと同じチェックを行いますが、今回はIDとして「channelInput」を使用します。一時的なチャネルを保持する定数値を作成しますが、先頭または末尾の空白は必ず削除してください。ここでsetChannelを呼び出すだけであれば、新旧のチャンネルが同じかどうかをチェックする必要はありません。

現在のURLも私たちが作成したものに変更するので、不要な重複があるためチェックが必要です。新しいチャネル名を含む新しい URL 文字列を作成することで、ユーザがページのリンクを共有しやすくなります。最後に、一時的なチャネルの状態を空の文字列に設定します。

```js
else if(event.target.id === "channelInput"){
  if (event.key === 'Enter') {
    //Navigates to new channels
    const newChannel = tempChannel.value.trim()
    if(newChannel){
      if(channel !== newChannel){
        //If the user isnt trying to navigate to the same channel theyre on
        setChannel(newChannel);
        let newURL = window.location.origin + "?channel=" + newChannel;
        window.history.pushState(null, '',newURL);
        tempChannel.setValue('');
      }
    }
  //What if there was nothing in newChannel?
}
```

ユーザがチャンネルを入力した場合はいいのですが、入力しなかった場合はどうでしょうか？ユーザーに間違いを警告するか、同じチャンネルに留まるか、あるいはデフォルトのチャンネルに移動させることができます。私は最後の選択肢を選びました。先ほどと同じようにチェックしますが、今回は「Global」を使い、チャンネルを設定します。

新しいURLを作成し、前と同じようにページ履歴にプッシュしますが、パラメータはつけません。アプリの冒頭に記載したコードがそれを認識し、デフォルトのチャンネルを使用します。もう一度、tempチャンネルを空の文字列に設定し、このコード・スニペットを最後の中括弧の前に置くことを確認してください。

```js
else{
  //If the user didnt put anything into the channel Input
  if(channel !== "Global"){
    //If the user isnt trying to navigate to the same channel theyre on
    setChannel("Global");
    let newURL = window.location.origin;
    window.history.pushState(null, '',newURL);
    tempChannel.setValue('');
  }
}
```

現在の URL をブラウザの戻るボタンの履歴に追加します。チャットが実際に戻るボタンを使用して前のチャンネル間を行き来するためには、さらにいくつかのことを行う必要があります。

前のチャンネル間のナビゲート
--------------

React チャットルームのすべての機能をセットアップしたので、ページを再レンダリングする機能を追加しましょう。ユーザがページ間を戻るか進むかをクリックしたときに、リロードの代わりに状態を変更します。

チャネルの URL をチェックし、"Global" または見つかったチャネルをチャネルの状態に設定する goBack という名前の関数を作成します。この関数は、ページにイベント・リスナーを追加しない限り実行されません！

```js
function goBack() {
  //Access the parameters provided in the URL
  let query = window.location.search.substring(1);
  if(!query){
    setChannel("Global")
  }else{
    let params = query.split("&");
    for(let i = 0; i < params.length;i++){
      var pair = params[i].split("=");
      //If the user input a channel then the default channel is now set
      //If not, we still navigate to the default channel.
      if(pair[0] === "channel" && pair[1] !== ""){
          setChannel(pair[1])
      }
    }
  }
}
```

ページがロードされたときだけリスナーを追加し、離れるときに削除したいのです。useEffectフックの別の使い方のようですね！別のフックを作りますが、第2引数に空の配列を渡します。さて、これはチャットの最初のロードごとに一度だけ実行されます。再レンダリングのたびに実行されることはありません。

window "にイベントリスナーを作成し、そのリスナーを削除するクリーンアップ関数を返します。イベントリスナーは "popstate "を待ちます。"popstate "はユーザーがブラウザの戻る/進むボタンをクリックした時です。最後に作った関数 "goBack "をイベント名の後に置く。これで、ページがリロードされることはなくなり、必要なときに必要なものが再レンダリングされるようになった！

```js
useEffect(() => {
  window.addEventListener("popstate",goBack);
  return function cleanup(){
    window.removeEventListener("popstate",goBack);
  }
},[]);
```

JSXを使ってReact UIを作る
------------------

さて、バックエンドで必要なロジックがすべて完成したので、シンプルでモダンなフロントエンドを作りましょう！ そのために、JavaScriptのUI記述言語 である[JSXを](https://reactjs.org/docs/introducing-jsx.html)返す 。コンポーネントと呼ばれるグループの中で、独自の変数やオブジェクトを使うことができる。構文はテンプレート・エンジンを使ったHTMLに似ていますが、JSXです！

変数／状態が変更されると、それを使用するコンポーネントは新しい値で再レンダリングされる。そのため、私たちのアプリは、変更があるとすぐに更新され、よりレスポンシブに感じられる。このため、PubNubとReactを一緒に使うのは素晴らしいアイデアです。PubNubはメッセージを高速に配信することができ、Reactはコンポーネントを更新することで遅れを取らない！

### アプリのデザイン

それではAppコンポーネントのデザインを考えてみよう。Material-UIは美しいコンポーネントを提供してくれる。以下のデザインを使って、ある領域でどのような関数が呼び出されているのかを確認しよう。

```js
return(
  <Card >
    <CardContent>
      <div className="top">
        <Typography variant="h4" inline >
          PubNub React Chat
          </Typography>
        <Input
          style={{width:'100px'}}
          className="channel"
          id="channelInput"
          onKeyDown={handleKeyDown}
          placeholder ={channel}
          onChange = {tempChannel.onChange}
          value={tempChannel.value}
        />
      </div>
      <div >
        <Log messages={messages}/>
      </div>
    </CardContent>
    <CardActions>
      <Input
        placeholder="Enter a message"
        fullWidth={true}
        id="messageInput"
        value={tempMessage.value}
        onChange={tempMessage.onChange}
        onKeyDown={handleKeyDown}
        inputProps={{'aria-label': 'Message Field',}}
        autoFocus={true}
      />
      <Button
        size="small"
        color="primary"
        onClick={publishMessage}
        >
        Submit
      </Button>
    </CardActions>
  </Card>
);
```

たくさんのデザインがあるように見えるかもしれませんが、いくつかの明確な要素を整理しているのです。

まず、Typographyコンポーネントの中にタイトルを配置します。その後、同じdiv内にチャンネルInputがあります。Inputには多くのプロパティがあり、それが取ることのできるアクションを定義します。ID、onKeyDownを処理する関数、プレースホルダ、onChange関数、値などです。

また、スタイルを参照する領域もあります。divの後には、まだ作成していないもうひとつの機能コンポーネントであるログがあります。このログはメッセージの配列を受け取り、配列が変更されるたびに再描画します。ログの後には、入力とボタンがあります。Inputはユーザーがメッセージを作成する場所です。そのプロパティに、それぞれの状態や変数を設定します。

また、オートフォーカスも設定します。ButtonのonClickをpublish message関数に設定し、ユーザーがメッセージを送信できるようにします。これでAppコンポーネントは終わりで、バックエンドは完成です。次に、メッセージを表示するために、さらに2つの小さなコンポーネントを作成する必要があります。

### ログとメッセージのデザイン

このアプリはチャットの動作の多くを定義していますが、それを完成させるためにさらに2つのコンポーネントが必要です。どちらもJSXを返し、メッセージがどのように表示されるかを整理します。最初のLogは、Typographyで満たされたListItemsのリストを表示します。これらのListItemsはメッセージのマップを繰り返し、Messageを出力する。配列のインデックスのキー、メッセージのuuid、メッセージのテキストを指定してMessageを作成します。

```js
function Log(props) {
  return(
    <List component="nav">
      <ListItem>
      <Typography component="div">
        { props.messages.map((item, index)=>(
          <Message key={index} uuid={item.uuid} text={item.text}/>
        )) }
      </Typography>
      </ListItem>
    </List>
  )
};
```

Messageコンポーネントは1つのメッセージを表し、uuidとテキストをコロンで区切って入れたdiv要素です。Appコンポーネントの子コンポーネントはpropsによってメッセージにアクセスします。子コンポーネントはメッセージを編集したり変更したりすることはできません。

これでコンポーネントの定義が完了したので、ファイルの一番下にエクスポートしてアプリを完成させる。index.jsのコードは、アプリをウェブページにレンダリングします！ プロジェクトフォルダ内の

```js
npm start
```

、 ブラウザで[localhost:3000に](localhost:3000) 移動 すると、 アプリが起動しているのがわかります！

```js
function Message(props){
  return (
    <div >
      { props.uuid }: { props.text }
    </div>
  );
}
export default App;
```

以下はチャットの動作のgifです：

[![react hooks chat gif](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1jkx/cadaa09d1dbce7a6f13e1fce08cc4a30/react-hooks-chat.gif)](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1jkx/cadaa09d1dbce7a6f13e1fce08cc4a30/react-hooks-chat.gif)

私たちは、ユーザーが好きなチャンネルでチャットができるアプリを作ることに成功しました。 完全な [コード・レポジトリもここにある](https://github.com/PubNubDevelopers/ReactHooksChat.PubNub)。

次は何をする？
-------

基本的なメッセージ機能が実装できたので、次はより多くの機能を追加しましょう！[チャットアプリを](https://www.pubnub.com/solutions/chat/)次のレベルに引き上げるための新しいチュートリアル、ベストプラクティス、デザインパターンを調べるには、[チャットソリューションページに](https://www.pubnub.com/solutions/chat/)向かいましょう。

  
**埋め込みコンテンツが**このページで**利用**できない場合は、[https://pubsub-quickstart-app.pubnub.com/signup](https://pubsub-quickstart-app.pubnub.com/signup)からも閲覧できます。

#### コンテンツ

[Pub/Subと履歴の取得はじめ](#h-0)に[React.jsとPubNubをインストールする](#h-2)[方法](#h-1)[React Hooksを使用する](#h-3)[理由](#h-2)[カスタムReact Hookを作成](#h-4)する[Reactコンポーネントを](#h-5)[デザインする](#h-4)[アプリコンポーネントを](#h-6)[セット](#h-5)[アップする：React Hooksを使ったステート](#h-6)[Reactで](#h-7)[Effectを使う](#h-6)[ReactでPubNubを](#h-8)[セット](#h-7)[アップするPub/Sub](#h-8)[:](#h-9)[PublishingReactイベントハンドラを](#h-10)[作成する](#h-9)[前のチャンネル間を](#h-11)[移動する](#h-10)[JSXを使ってReact UIAppを](#h-12)[デザインする](#h-13)[ログとメッセージのデザイン](#h-14)[次は？](#h-15)

PubNubはどのように役立つのか？
==================

この記事は[PubNub.com](https://www.pubnub.com/blog/creating-a-chat-window-using-react-and-hooks/)に掲載されたものです。

PubNubのプラットフォームは、開発者がWebアプリ、モバイルアプリ、IoTデバイス向けにリアルタイムのインタラクティブ機能を構築、提供、管理できるように支援します。

私たちのプラットフォームの基盤は、業界最大かつ最もスケーラブルなリアルタイムエッジメッセージングネットワークです。世界15か所以上で8億人の月間アクティブユーザーをサポートし、99.999%の信頼性を誇るため、停電や同時実行数の制限、トラフィックの急増による遅延の問題を心配する必要はありません。

PubNubを体験
---------

[ライブツアーを](https://www.pubnub.com/tour/introduction/)チェックして、5分以内にすべてのPubNub搭載アプリの背後にある本質的な概念を理解する

セットアップ
------

[PubNubアカウントに](https://admin.pubnub.com/signup/)サインアップすると、PubNubキーに無料ですぐにアクセスできます。

始める
---

[PubNubのドキュメントは](https://www.pubnub.com/docs)、ユースケースや[SDKに](https://www.pubnub.com/docs)関係なく、あなたを立ち上げ、実行することができます。