# React と MQTT.js SDK を使ったデプロイメントへの接続

本記事では、React フレームワーク上で構築されたウェブアプリケーションにおいて MQTT.js を使用し、クライアントと MQTT ブローカー間の接続、サブスクライブ、メッセージ送受信、サブスクライブ解除などの機能を実装する方法を主に紹介します。

## 前提条件

### MQTT ブローカーのデプロイ

- EMQX が提供する[無料のパブリック MQTT ブローカー](https://www.emqx.com/en/mqtt/public-mqtt5-broker)を利用できます。このサービスは[EMQX プラットフォーム](https://www.emqx.com/en)を基に作成されています。ブローカーへのアクセス情報は以下の通りです：
  - アドレス：**broker.emqx.io**
  - WebSocket ポート：**8083**
  - TLS/SSL 対応 WebSocket ポート：**8084**
- また、[独自の MQTT ブローカーを作成](../create/overview.md)することも可能です。デプロイメントが稼働状態になった後、デプロイメント概要ページで接続情報を確認できます。後のクライアント接続段階で必要となるユーザー名とパスワードは、**アクセス制御** -> **[認証](../deployments/default_auth.md)** から設定可能です。

### React アプリケーションの作成

参考リンク：[https://reactjs.org/docs/getting-started.html](https://reactjs.org/docs/getting-started.html)

- `Create React App` を使った新規 React アプリケーションの作成

  ```shell
  npx create-react-app react-mqtt-test
  ```

  TypeScript を使用する場合は、コマンドの末尾に `--template typescript` パラメータを追加します。

  ```shell
  npx create-react-app react-mqtt-test --template typescript
  ```

  さらに、React プロジェクトに必要な TypeScript 型ライブラリを追加します。

  ```shell
  npm install --save typescript @types/node @types/react @types/react-dom @types/jest
  # または
  yarn add typescript @types/node @types/react @types/react-dom @types/jest
  ```

  TypeScript の使用は本記事の例の主題ではありませんが、必要に応じて作成例や完全なコード例を参考にして TypeScript 機能を追加できます。

- CDN 経由でのインポート

  ```html
  <script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
  <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
  ```

## 依存関係のインストール

[MQTT.js](https://github.com/mqttjs/MQTT.js) は、JavaScript で書かれた MQTT プロトコル用の完全オープンソースのクライアントサイドライブラリで、Node.js とブラウザの両方で利用可能です。`MQTT.js` の詳細や使い方は [MQTT.js GitHub](https://github.com/mqttjs/MQTT.js#table-of-contents) をご参照ください。

MQTT.js は NPM または Yarn でインストール可能で、CDN や相対パス経由でのインポートも可能です。本例では NPM コマンドによるインストールを行います。CDN 経由で React を使用するプロジェクトには直接ファイルをインポートする方法が適しています。

1. コマンドラインから npm または yarn のいずれかでインストール

   ```shell
   npm install mqtt --save
   # または
   yarn add mqtt
   ```

2. CDN 経由でのインポート

   ```html
   <script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>
   ```

3. ローカルにダウンロードし、相対パスでインポート

   ```html
   <script src="/your/path/to/mqtt.min.js"></script>
   ```

## WebSocket ポートでの接続

クライアント ID、ユーザー名、パスワードを以下のように設定できます。クライアント ID は一意である必要があります。

```js
const clientId = "emqx_react_" + Math.random().toString(16).substring(2, 8);
const username = "emqx_test";
const password = "emqx_test";
```

以下のコードでクライアントと MQTT ブローカー間の接続を確立できます。

```js
const client = mqtt.connect("ws://broker.emqx.io:8083/mqtt", {
  clientId,
  username,
  password,
  // ...その他のオプション
});
```

## WebSocket セキュアポートでの接続

TLS/SSL 暗号化が有効な場合、接続の[パラメーターオプション](https://github.com/mqttjs/MQTT.js#mqttclientstreambuilder-options)は WebSocket ポート経由の接続と同じですが、プロトコルを `wss` に変更し、正しいポート番号に合わせる必要があります。

以下のコードでクライアントと MQTT ブローカー間の接続を確立できます。

```js
const client = mqtt.connect("wss://broker.emqx.io:8084/mqtt", {
  clientId,
  username,
  password,
  // ...その他のオプション
});
```

## サブスクライブとパブリッシュ

### トピックのサブスクライブ

サブスクライブするトピックと対応する[QoSレベル](https://www.emqx.com/zh/blog/introduction-to-mqtt-qos)を指定します。

```javascript
const mqttSub = (subscription) => {
    if (client) {
      const { topic, qos } = subscription
      client.subscribe(topic, { qos }, (error) => {
        if (error) {
          console.log('Subscribe to topics error', error)
          return
        }
        console.log(`Subscribe to topics: ${topic}`)
        setIsSub(true)
      })
    }
  }
```

### トピックのサブスクライブ解除

以下のコードで、サブスクライブ解除するトピックと対応する QoS レベルを指定して解除できます。

```javascript
const mqttUnSub = (subscription) => {
  if (client) {
    const { topic, qos } = subscription
    client.unsubscribe(topic, { qos }, (error) => {
      if (error) {
        console.log('Unsubscribe error', error)
        return
      }
      console.log(`unsubscribed topic: ${topic}`)
      setIsSub(false)
    })
  }
}
```

### メッセージのパブリッシュ

メッセージをパブリッシュする際は、MQTT ブローカーに対象のトピックとメッセージ内容を渡す必要があります。

```javascript
const mqttPublish = (context) => {
  if (client) {
    const { topic, qos, payload } = context;
    client.publish(topic, payload, { qos }, (error) => {
      if (error) {
        console.log("Publish error: ", error);
      }
    });
  }
};
```

### メッセージの受信

以下のコードはメッセージイベントを監視し、メッセージ受信時に受信したメッセージとトピックをコンソールに出力します。

```js
client.on("message", (topic: string, message) => {
  console.log(`received message: ${message} from topic: ${topic}`);
});
```

### MQTT ブローカーからの切断

クライアントをブローカーから切断するには、以下のコードを使用します。

```javascript
const mqttDisconnect = () => {
  if (client.connected) {
    try {
      client.end(false, () => {
        setConnectStatus('Connect')
        console.log('disconnected successfully')
      })
    } catch (error) {
      console.log('disconnect error:', error)
    }
  }
}
```

上記は主要なコードスニペットの一部のみを示しています。完全なプロジェクトコードは [MQTT Client - React](https://github.com/emqx/MQTT-Client-Examples/tree/master/mqtt-client-React) をご参照ください。ダウンロードして実際に試すことが可能です。

## 接続のテスト

React を使って接続作成、トピックのサブスクライブ、メッセージの送受信、サブスクライブ解除、切断ができる簡単なブラウザアプリケーションを作成しました。

![reactmqttpage.png](https://assets.emqx.com/images/d1c51195c056f3b4afb267edaeb217f0.png)

別のクライアントとして [MQTT 5.0 クライアントツール - MQTTX](https://mqttx.app/) を使い、メッセージの送受信テストを行います。

![reactmqttx.png](https://assets.emqx.com/images/621ba9544ea69f9ee7b24203846d0409.png)

MQTTX はブラウザ側からのメッセージを正常に受信できることが確認でき、MQTTX からトピックへメッセージ送信した際の様子も確認できます。

![reactmqtttest.png](https://assets.emqx.com/images/da008ae3544a83a3efa78266190ea364.png)

## FAQ

1. 自己署名証明書の使い方は？双方向 TLS/SSL 認証は使えますか？

   ブラウザの制限により、現時点ではサポートされていません。詳細は MQTT.js の issue をご参照ください：[ブラウザでの TLS/SSL 双方向認証接続の使い方](https://github.com/mqttjs/MQTT.js/issues/1515)、および [Node.js では双方向認証可能だがブラウザは非対応](https://github.com/mqttjs/mqtt.js/issues/741)。

## まとめ

本記事では、React プロジェクト内で MQTT 接続を作成し、クライアントと MQTT サーバー間でのサブスクライブ、メッセージパブリッシュ、サブスクライブ解除、切断のシナリオをシミュレーションしました。

React v18.2.0 を使用しているため、例示コードは Hook コンポーネント機能を用いています。必要に応じて、完全な例の `ClassMqtt` コンポーネントを参照し、クラスコンポーネント機能を使ったプロジェクト構築も可能です。

完全なサンプルソースコードは [MQTT Client - React ページ](https://github.com/emqx/MQTT-Client-Examples/tree/master/mqtt-client-React)からダウンロード可能です。また、他言語でのデモ例も [MQTT Client example ページ](https://github.com/emqx/MQTT-Client-Examples)で多数公開していますので、ぜひご覧ください。
