arrow一覧に戻る

2021.10.01

Amplifyで簡単に作れるリアルタイムチャット機能

新規サービス構築のご相談を受ける時に、チャット機能をご要望されるお客様が増えてきました。

チャット機能といえばリアルタイム性が重要ですね。
ブラウザのリロードボタンを押さないと画面が最新化されないなんて作りは、まず許されません。
ブラウザのリロードや画面遷移を行わず、リアルタイムで画面に最新データを表示する方法はいくつかあります。

 

a) ポーリングによる一定間隔でのデータ取得

Webアプリケーションで一般的に使われるHTTP(HTTPS)は、クライアント主導でサーバとの1回のやり取りで処理が完結します。そのためサーバ主導でクライアントへ通知する事ができません。
HTTP(HTTPS)を使い、一定間隔でクライアントからサーバに対してデータ取得のリクエストを行い、画面を最新化します。 特別なアーキテクチャを必要しない反面、頻繁にデータを取得すれば通信量が増えますし、データ取得の間隔を長くしてしまうとリアルタイム性が損なわれてしまいます。
アーキテクチャの縛りがあったり、短期間で対応する場合に採用する事が多いと思います。

b) WebSocketによる双方通信

WebSocketは、クライアントとサーバの間にコネクションを確立し、クライアント・サーバの双方向から通信を行なう事ができます。
これにより、データ更新があればサーバ主導でクライアントにデータを送る事が可能です。

 

今回は、b)を簡単に実現できる AWSのAmplify+AppSyncで、簡易リアルタイムチャットアプリを作成してみます。

リアルタイムという所に主眼を置き、なるべく短いコードで紹介します。
ユーザー登録、ログインといった機能は省略しますのでご了承ください。

Amplify+AppSyncによる簡易リアルタイムチャットの構成

今回のAWSインフラ構成は以下の通りとなります。

インフラ構築はすべてAmplifyを通して行ないます。

Amplifyについては、以下の記事で軽く紹介しているので、何それ?という方は合わせてご確認ください。

2020.05.20

Amplifyを使って完全サーバレスなWebアプリを作る

 

この先は、以下の流れで説明していきます。

  1. セットアップ
  2. AWSインフラ構築
  3. 実装
  4. 動作確認

セットアップ

まずは、ReactとAmplifyが使えるようにします。

私の開発環境は以下となりますが、バージョン依存する仕組みはあまり使ってないので、多少古かったり新しかったしても大丈夫だと思います。

  • MacOS Big Sur (11.5.2)
  • npm (6.14.11)
  • node.js (v16.9.1) ※執筆時点の最新安定版

Node.jsのインストール

既にnpm や node.js がインストールされている場合、この手順はスキップして貰って結構です。
また、node.jsをインストールする事が目的なので、この方法以外でインストールしても問題ありません。

 

Homebrewのインストール

$ /bin/bash -c "$(curl -fsSL <https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh>)"

nodebrewのインストール

$ brew install nodebrew

Node.jsのインストール

$ nodebrew install-binary stable

インストールされたNode.jsのバージョンを確認

$ nodebrew ls 
v14.16.0 
v16.9.1

バージョンを指定して有効化

$ nodebrew use 16.9.1

バージョンを確認

$ node -v
v16.9.1

AmplifyとReactをインストール

続いてAmplifyとReactをインストールします。TypeScriptも使うようにしておきます。

$ npm install -g create-react-app 
$ create-react-app chatsample --template typescript 
$ cd chatsample 
$ npm install aws-amplify 
$ npm install aws-amplify-react

一旦、ここでReactのサンプルページが表示される事を確認しておきましょう。

$ npm start
Compiled successfully! 
You can now view chat-sample in the browser. 
  Local: http://localhost:3000 
  On Your Network: http://192.168.0.4:3000

おそらく自動的にブラウザが起動してReactのサンプルページが表示されるかと思います。
表示なれない場合は、ブラウザを起動して、 http://localhost:3000 にアクセスしてください。

確認できたら、control + c でアプリを止めておきましょう。

インフラ構築

次にAWSのインフラ構築を行っていきます。
Amplifyを使えばAWSのサービスについて詳しく無い方でも、AWSのアカウントさえ持っていれば簡単に構築できます。
インフラやバックエンドをあまり意識しなくて済むのは助かりますね。

Amplify CLIをインストール

AmplifyのCLI(コマンドラインインタフェース)をインストールします。

npm install -g @aws-amplify/cli

AWSインフラ構築

事前に、AWSアカウントと、プログラムによるアクセス可能(※1)なAdministratorAccessポリシー(※2)を持つ、IAMユーザーを用意しておいてください。

※1 詳細は割愛しますが、IAMユーザー追加の画面で、「プログラムによるアクセス」にチェックして作成します。

IAM

※2 厳密にはAdministratorAccessの必要はありませんが、説明を簡略化する為にフルアクセス可能な権限を与えています。

 

AWSの認証情報を登録します。(IAMユーザーのアクセスキーとシークレットアクセスキーを登録)

$ aws configure --profile chat-sample 
AWS Access Key ID [None]: AKIXXXXXXXXXXXXXXX 
AWS Secret Access Key [None]: HogeXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 
Default region name [None]: ap-northeast-1 
Default output format [None]: json

Amplify CLIを使って、AWSのインフラを構築していきます。
対話形式で行われますが基本的にデフォルトのままで大丈夫です。

$ amplify init
Note: It is recommended to run this command from the root of your app directory
? Enter a name for the project chatsample
The following configuration will be applied:

Project information
| Name: chatsample
| Environment: dev
| Default editor: Visual Studio Code
| App type: javascript
| Javascript framework: react
| Source Directory Path: src
| Distribution Directory Path: build
| Build Command: npm run-script build
| Start Command: npm run-script start

? Initialize the project with the above configuration? Yes
Using default provider  awscloudformation
? Select the authentication method you want to use: AWS profile

For more information on AWS Profiles, see:
<https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html>

? Please choose the profile you want to use chat-sample
Adding backend environment dev to AWS Amplify Console app: d1vglm09r4cfh5
⠦ Initializing project in the cloud...

〜〜省略〜〜

CREATE_COMPLETE amplify-chatsample-dev-221643 AWS::CloudFormation::Stack Mon Sep 13 2021 22:17:17 GMT+0900 (日本標準時) 
✔ Successfully created initial AWS cloud resources for deployments.
✔ Initialized provider successfully.
Initialized your environment successfully.

Your project has been successfully initialized and connected to the cloud!

Some next steps:
"amplify status" will show you what you've added already and if it's locally configured or deployed
"amplify add <category>" will allow you to add features like user login or a backend API
"amplify push" will build all your local backend resources and provision it in the cloud
"amplify console" to open the Amplify Console and view your project status
"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud

Pro tip:
Try "amplify add api" to create a backend API and then "amplify publish" to deploy everything

次にAPIを追加します。(まだAWS上には構築されません)
こちらも基本的にデフォルト設定でOKですが、 ? After how many days from now the API key should expire (1-365)  という箇所だけ365に変更しています。

$ amplify add api
? Please select from one of the below mentioned services: GraphQL
? Provide API name: chatsample
? Choose the default authorization type for the API API key
? Enter a description for the API key: 
? After how many days from now the API key should expire (1-365): 365
? Do you want to configure advanced settings for the GraphQL API No, I am done.
? Do you have an annotated GraphQL schema? No
? Choose a schema template: Single object with fields (e.g., “Todo” with ID, name, description)

The following types do not have '@auth' enabled. Consider using @auth with @model
         - Todo
Learn more about @auth here: <https://docs.amplify.aws/cli/graphql-transformer/auth>

GraphQL schema compiled successfully.

Edit your schema at /Users/ryuji-yamamoto/Documents/Develop/blog-post/chatsample/amplify/backend/api/chatsample/schema.graphql or place .graphql files in a directory at /Users/ryuji-yamamoto/Documents/Develop/blog-post/chatsample/amplify/backend/api/chatsample/schema
? Do you want to edit the schema now? No
Successfully added resource chatsample locally

Some next steps:
"amplify push" will build all your local backend resources and provision it in the cloud
"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud

今回はAPIアクセス時のセキュリティにAPI keyを使っています。
これは最大365日まで使えるキーですが、開発用という位置づけなので、本格的に開発する時はCognitoなどの利用を検討してください。

 

では、AWS上に反映させます。(少し時間が掛かります)

$ amplify push
✔ Successfully pulled backend environment dev from the cloud.

    Current Environment: dev
    
┌──────────┬───────────────┬───────────┬───────────────────┐
│ Category │ Resource name │ Operation │ Provider plugin   │
├──────────┼───────────────┼───────────┼───────────────────┤
│ Api      │ chatsample    │ Create    │ awscloudformation │
└──────────┴───────────────┴───────────┴───────────────────┘
? Are you sure you want to continue? Yes

The following types do not have '@auth' enabled. Consider using @auth with @model
	 - Todo
Learn more about @auth here: <https://docs.amplify.aws/cli/graphql-transformer/auth>

GraphQL schema compiled successfully.

Edit your schema at /Users/ryuji-yamamoto/Documents/Develop/blog-post/chatsample/amplify/backend/api/chatsample/schema.graphql or place .graphql files in a directory at /Users/ryuji-yamamoto/Documents/Develop/blog-post/chatsample/amplify/backend/api/chatsample/schema
? Do you want to generate code for your newly created GraphQL API Yes
? Choose the code generation language target typescript
? Enter the file name pattern of graphql queries, mutations and subscriptions src/graphql/**/*.ts
? Do you want to generate/update all possible GraphQL operations - queries, mutations and subscriptions Yes
? Enter maximum statement depth [increase from default if your schema is deeply nested] 2
? Enter the file name for the generated code src/API.ts
⠼ Updating resources in the cloud. This may take a few minutes...

AWSの管理コンソールを開くと、Amplify、AppSync、DynamoDBが構築されている事がわかります。(単なる確認だけなので見なくても大丈夫です)

 

Amplify

Amplify

AppSync

AppSync

DynamoDB

DynamoDBのテーブルは、AmplifyでAPIを追加した時に自動生成されたサンプルテーブルです。

実装

インフラ構築が終わったところで、ここからは実装を進めていきます。

今回はReactを使って進めますが、AmplifyはVueやAngular、Flutterなど沢山の言語、プラットフォームに対応しています。Reactを駆使した実装という訳では無いので、他言語・プラットフォームでも参考になるかと思います。

投稿機能の作成

まずはテキストを入力して投稿する機能と、投稿したテキストを表示する機能だけ実装しましょう。

※リアルタイム更新は後で実装します。

AppSyncのスキーマ定義

AmplifyのAPI作成時に、サンプル用のスキーマ定義が用意されているので、こちらを修正しましょう。

 

~/amplify/backend/api/chatsample/schema.graphql を開きます。

type Todo @model {
  id: ID!
  name: String!
  description: String
}

↓以下の通り修正します。(もとのコードは削除します)

type ChatMessage @model {
  id: ID!
  message: String!
}

AmplifyにPushします(AWSインフラに反映します)

$ amplify push
✔ Successfully pulled backend environment dev from the cloud.

    Current Environment: dev
    
┌──────────┬───────────────┬───────────┬───────────────────┐
│ Category │ Resource name │ Operation │ Provider plugin   │
├──────────┼───────────────┼───────────┼───────────────────┤
│ Api      │ chatsample    │ Update    │ awscloudformation │
└──────────┴───────────────┴───────────┴───────────────────┘
? Are you sure you want to continue? Yes

The following types do not have '@auth' enabled. Consider using @auth with @model
	 - ChatMessage
Learn more about @auth here: <https://docs.amplify.aws/cli/graphql-transformer/auth>

GraphQL schema compiled successfully.

Edit your schema at /Users/ryuji-yamamoto/Documents/Develop/blog-post/chatsample/amplify/backend/api/chatsample/schema.graphql or place .graphql files in a directory at /Users/ryuji-yamamoto/Documents/Develop/blog-post/chatsample/amplify/backend/api/chatsample/schema
? Do you want to update code for your updated GraphQL API Yes
? Do you want to generate GraphQL statements (queries, mutations and subscription) based on your schema types?
This will overwrite your current graphql queries, mutations and subscriptions Yes
⠇ Updating resources in the cloud. This may take a few minutes...

Do you want to update code for your updated GraphQL API のところでYes(デフォルト)を選択することで、フロントエンドからAPIを使用する時に利用できるコードが自動生成(変更)されます。

  • src/graphql/mutations.ts : 更新系API
  • src/graphql/queries.ts : 取得系API
  • src/graphql/subscriptions.ts : 更新通知系API

DynamoDBにテーブルが作成されている事も確認できます。(もともとあったTodoテーブルは削除されています)

フロントエンド実装

フロントエンド(画面)の実装を進めていきましょう。

簡易アプリという事でデザインは簡易なものにします。
今回はMaterial UIというUIコンポーネントライブラリを使っていきます。

npm add @material-ui/core

以下のコマンドで、APIに対応するModelを自動生成します。

amplify codegen models

src/models配下にいくつかファイルがされたと思います。TypeScriptの型定義もしてくれるので便利です。

models

 

src/App.tsx を開いて画面のコードを書いていきましょう。

import React, { useEffect, useState } from "react";
import "./App.css";
import { Box, Button, TextField, Chip } from "@material-ui/core";
import awsConfig from "./aws-exports";
import Amplify, { API, graphqlOperation } from "aws-amplify";
import { ChatMessage } from "./models";
import { listChatMessages } from "./graphql/queries";
import { createChatMessage } from "./graphql/mutations";
import { ListChatMessagesQuery } from "./API";

Amplify.configure(awsConfig);

const styles = {
  main: {
    margin: 16,
    height: 504,
    overflow: "auto",
  },
  footer: {
    margin: 16,
    marginLeft: 24,
    height: 64,
  },
  message: {
    margin: 8,
    padding: 8,
    display: "flex",
    width: 300,
  },
  messageInput: {
    width: 300,
    marginRight: 8,
  },
};

function App() {
  const [chatMessages, setChatMessages] = useState<ChatMessage[]>([]);
  const [inputMessage, setInputMessage] = useState<string>("");

  useEffect(() => {
    fetchData();
  }, []);

  async function fetchData() {
    const items = await API.graphql(graphqlOperation(listChatMessages));
    if ("data" in items && items.data) {
      const messages = items.data as ListChatMessagesQuery;
      setChatMessages(
        sortMessage(messages.listChatMessages?.items as ChatMessage[])
      );
    }
  }

  async function saveData() {
    const model = new ChatMessage({
      message: inputMessage,
    });
    await API.graphql(
      graphqlOperation(createChatMessage, {
        input: model,
      })
    );
    setInputMessage("");
  }

  function sortMessage(messages: ChatMessage[]) {
    return [...messages].sort(
      (a, b) =>
        new Date(a.createdAt!).getTime() - new Date(b.createdAt!).getTime()
    );
  }

  function onChange(messge: string) {
    setInputMessage(messge);
  }

  return (
    <>
      <Box style={styles.main}>
        {chatMessages &&
          chatMessages.map((message, index) => {
            return (
              <Chip
                key={index}
                label={message.message}
                color="primary"
                style={styles.message}
              />
            );
          })}
      </Box>
      <Box style={styles.footer}>
        <TextField
          variant="outlined"
          type="text"
          color="primary"
          size="small"
          value={inputMessage}
          style={styles.messageInput}
          onChange={(e) => onChange(e.target.value)}
          placeholder="メッセージを入力"
        />
        <Button variant="contained" color="default" onClick={() => saveData()}>
          投稿
        </Button>
      </Box>
    </>
  );
}

export default App;

何か長くなってしまいましたが、Amplifyが絡む箇所はあまり多くありませんので抜粋して説明します。

 

まずは入力データを投稿する処理から。

async function saveData() {
    const model = new ChatMessage({
      message: inputMessage,
    });
    await API.graphql(
      graphqlOperation(createChatMessage, {
        input: model,
      })
    );
    setInputMessage("");
  }

投稿ボタンを押すと上記処理が呼ばれます。
画面で入力したデータ(inputMessage)をモデルにセットし、API.graphqlを使って、createChatMessageという更新系API(mutation)を呼び出します。

createChatMessageは、自動生成された src/graphql/mutations.ts に定義されています。

export const createChatMessage = /* GraphQL */ `
  mutation CreateChatMessage(
    $input: CreateChatMessageInput!
    $condition: ModelChatMessageConditionInput
  ) {
    createChatMessage(input: $input, condition: $condition) {
      id
      message
      createdAt
      updatedAt
    }
  }
`;

createChatMessageの第一引数 input に、画面で入力した messageを入れて呼び出しています。
尚、id, createAd, updateAtは自動的に入るので意識しなくて大丈夫です。

inputの型である、3行目のCreateChatMessageInputは、自動生成された src/API.ts に定義されています。

export type CreateChatMessageInput = {
  id?: string | null,
  message: string,
};

画面の初期表示時にデータを取得する箇所も見ておきましょう。

async function fetchData() {
    const items = await API.graphql(graphqlOperation(listChatMessages));
    if ("data" in items && items.data) {
      const messages = items.data as ListChatMessagesQuery;
      setChatMessages(
        sortMessage(messages.listChatMessages?.items as ChatMessage[])
      );
    }
  }

こちらも API.graphql を使い、listChatMessages というデータ取得系API(query)を呼び出しています。

APIの戻り値から実際にリストを取り出すのが若干面倒で、 items.data.listChatMessages.items のように、 ~.data.{API名}.items という方法で取り出します。

 

listChatMessagesは、自動生成された src/graphql/queries.ts に定義されています。

export const listChatMessages = /* GraphQL */ `
  query ListChatMessages(
    $filter: ModelChatMessageFilterInput
    $limit: Int
    $nextToken: String
  ) {
    listChatMessages(filter: $filter, limit: $limit, nextToken: $nextToken) {
      items {
        id
        message
        createdAt
        updatedAt
      }
      nextToken
    }
  }
`;

コードの中身が確認できたらコードを保存し、以下のコマンドでWebアプリを実行します。

npm start

入力欄と投稿ボタンだけの超簡易画面です。
メッセージを入れて投稿ボタンを押してみます。

初期表示時にしかデータを取得していないので、ブラウザでリロードをしてみましょう。

投稿したデータが表示されましたね。

AWSの管理コンソールからDyanamoDBのテーブルを見ると、データが登録されている事が確認できます。

リアルタイム反映機能の作成

ここから本題のリアルタイム反映機能を実装していきます。

実は自動生成されたコードの中には既に、データ更新の通知を受ける仕組みも準備されています。
サブスクプションと呼ばわるこの機能は、データの登録や削除といった更新系API(mutation)を購読することで、購読対象の更新処理が呼ばれるとリアルタイムに通知を受ける事が可能です。

今回は投稿だけの簡易チャットなので、データ登録のサブスクプションを使用します。

 

src/App.tsx を開いて以下の通り書き換えてください。

import React, { useEffect, useState } from "react";
import "./App.css";
import { Box, Button, TextField, Chip } from "@material-ui/core";
import awsConfig from "./aws-exports";
import Amplify, { API, graphqlOperation } from "aws-amplify";
import { ChatMessage } from "./models";
import { listChatMessages } from "./graphql/queries";
import { createChatMessage } from "./graphql/mutations";
import { onCreateChatMessage } from "./graphql/subscriptions";
import { ListChatMessagesQuery, OnCreateChatMessageSubscription } from "./API";

Amplify.configure(awsConfig);

type SubscriptionEvent = { value: { data: OnCreateChatMessageSubscription } };

const styles = {
  main: {
    margin: 16,
    maxHeight: 504,
    overflow: "auto",
  },
  footer: {
    margin: 16,
    marginLeft: 24,
    height: 64,
  },
  message: {
    margin: 8,
    padding: 8,
    display: "flex",
    width: 300,
  },
  messageInput: {
    width: 300,
    marginRight: 8,
  },
};

function App() {
  const [chatMessages, setChatMessages] = useState<ChatMessage[]>([]);
  const [inputMessage, setInputMessage] = useState<string>("");

  useEffect(() => {
    fetchData();

    // unsubscribe(購読解除)で型エラーが出るので今回はanyで受ける
    const onCreate: any = API.graphql(graphqlOperation(onCreateChatMessage));

    onCreate.subscribe({
      next: ({ value: { data } }: SubscriptionEvent) => {
        // 更新されたデータをリストに追加
        const newMessage: ChatMessage = data.onCreateChatMessage!;
        setChatMessages((prevMessages) =>
          sortMessage([...prevMessages, newMessage])
        );
      },
    });

    return () => {
      // 画面を離れる時に購読解除する
      onCreate.unsubscribe();
    };
  }, []);

  async function fetchData() {
    const items = await API.graphql(graphqlOperation(listChatMessages));
    if ("data" in items && items.data) {
      const messages = items.data as ListChatMessagesQuery;
      setChatMessages(
        sortMessage(messages.listChatMessages?.items as ChatMessage[])
      );
    }
  }

  async function saveData() {
    const model = new ChatMessage({
      message: inputMessage,
    });
    await API.graphql(
      graphqlOperation(createChatMessage, {
        input: model,
      })
    );
    setInputMessage("");
  }

  function sortMessage(messages: ChatMessage[]) {
    return [...messages].sort(
      (a, b) =>
        new Date(a.createdAt!).getTime() - new Date(b.createdAt!).getTime()
    );
  }

  function onChange(messge: string) {
    setInputMessage(messge);
  }

  return (
    <>
      <Box style={styles.main}>
        {chatMessages &&
          chatMessages.map((message, index) => {
            return (
              <Chip
                key={index}
                label={message.message}
                color="primary"
                style={styles.message}
              />
            );
          })}
      </Box>
      <Box style={styles.footer}>
        <TextField
          variant="outlined"
          type="text"
          color="primary"
          size="small"
          value={inputMessage}
          style={styles.messageInput}
          onChange={(e) => onChange(e.target.value)}
          placeholder="メッセージを入力"
        />
        <Button variant="contained" color="default" onClick={() => saveData()}>
          投稿
        </Button>
      </Box>
    </>
  );
}

export default App;

リアルタイム反映部分に絞って説明します。

  useEffect(() => {
		〜省略〜

    // unsubscribe(購読解除)で型エラーが出るので今回はanyで受ける
    const onCreate: any = API.graphql(graphqlOperation(onCreateChatMessage));

		〜省略〜
  }, []);

画面の初期化時に、毎度おなじみ API.graphql を使い、onCreateChatMessage というデータ更新通知系API(query)を呼び出します。

コメントに書いていますが、TypeScriptでの型解決がうまくいかないので、今回は結果をanyで受けています。
(ちゃんと解決すべきところですが本題と関係ないので端折りました。)

 

onCreateChatMessageは、 /src/graphql/subscriptions.ts で以下のように定義されています。

export const onCreateChatMessage = /* GraphQL */ `
  subscription OnCreateChatMessage {
    onCreateChatMessage {
      id
      message
      createdAt
      updatedAt
    }
  }
`;

この定義だけでは何をやっているか分からないと思うので、AppSyncのスキーマ定義を見てみます。

 

赤枠部分を抜粋します。

onCreateChatMessage: ChatMessage
		@aws_subscribe(mutations: ["createChatMessage"])

onCreateChatMessageは、mutationのcreateChatMessageを購読し、更新があったら ChatMessage を返すよ。という定義になっています。

既に説明しましたが、 createChatMessageは、投稿ボタンを押した時に呼ばれるデータ更新系APIです。
投稿データが登録されたタイミングで、 onCreateChatMessage を通じて更新後のデータ(ChatMessage)を取得できるという訳ですね。

 

コードの説明に戻ります。

  useEffect(() => {
		〜省略〜

    onCreate.subscribe({
      next: ({ value: { data } }: SubscriptionEvent) => {
        // 更新されたデータをリストに追加
        const newMessage: ChatMessage = data.onCreateChatMessage!;
        setChatMessages((prevMessages) =>
          sortMessage([...prevMessages, newMessage])
        );
      },
    });

		〜省略〜
  }, []);
onCreateChatMessageによって返却される更新データを、dataとして受け取ります。

受け取った更新データは、既存のデータとマージし、ソート(sortMessage)して画面に反映されます。

 

最後に、購読解除の処理も見ておきます。

  useEffect(() => {
		〜省略〜
		return () => {
      // 画面を離れる時に購読解除する
      onCreate.unsubscribe();
    };
  }, []);

実はこの処理、今回の簡易チャットアプリでは必要のない処理です。(有っても無くても動作は同じ)

何故入れているかというと、例えばSPA(シングルページアプリケーション)で、HTMLの再読み込み無しに画面を行ったり来たりすると購読処理が何度も行われてしまいます。
1回のデータ登録に対して複数回の通知が来るので、データを重複処理してしまう危険性があります。
ですので画面を離れる時など、購読が不要になるタイミングで解除するようにしましょう。

動作確認

チャットメッセージを投稿し、リアルタイムで画面に反映する機能を作成しました。

ブラウザを複数立ち上げて、片方で投稿したメッセージが、もう片方にリアルタイム反映される事を確認してみましょう。

左のブラウザにメッセージを入力して、投稿ボタンを押すと・・・

画面4

右のブラウザにも自動反映されました!(ブラウザのリロードはしていません)

最後に

いかがでしょうか?

Amplifyを使えば、少ないコードでリアルタイム反映(通知)を実現可能なことがお分かりいただけたかと思います。

今回のサンプルアプリは、ユーザー管理機能を含んでいないのでチャット機能としては不十分ですが、Amplifyを使えばユーザー管理や認証も簡単に実現できます。

AWSインフラとしてAppSync、DynamoDBを使っていますが、今回の記事ではあえて詳しい説明を省いています。(もしご要望が多ければ改めてしっかり書きます)
インフラやバックエンドを意識せず、フロントエンドエンジニアでも(少し勉強すれば)扱い易いのも、Amplifyのメリットですね。

この記事を書いた人

山本 竜二 IT アーキテクト

新卒の時に、大手運送会社の基幹システムの開発・運用を担当。以後、常に新しい技術に触れられる環境を求めて何度かの転職を経験し、NCDC株式会社を経て、Fixel株式会社のスターティングメンバーとして参画。 Fixel株式会社ではITアーキテクトとして、多数のプロジェクトの要件定義から設計、実装まで幅広く担当。 AWSを使ったインフラ設計・構築も得意としており、UX/UIデザインだけではなく、インフラ構築からアプリ開発まで、シームレスに一貫したサービスを提供することを支えている。

Contact

どのようなお悩みでも
まずはお気軽に
ご相談ください

arrow

Careers

柔軟で先進的な思考を持った
デザイナーやエンジニア、
コンサルタントを募集しています

arrow

Copyright© Fixel Inc. All rights reserved.