リアルタイムイベントの購読
このガイドでは、リアルタイムデータ統合を有効にする利点と、これらのサブスクリプションを設定およびフィルターする方法について説明します。また、サブスクリプションの購読解除方法についても取り上げます。
開始する前に、以下が必要です:
- APIに接続されたアプリケーション
- 変更対象のデータが既に作成されていること
リアルタイムリストクエリの設定
リストデータをフェッチする推奨方法は、observeQueryを使用してアプリデータをすべて常にリアルタイムで取得することです。observeQueryをReactのuseStateおよびuseEffectフックと統合するには、次のようにします:
import { useState, useEffect } from 'react';import { generateClient } from 'aws-amplify/data';import type { Schema } from '../amplify/data/resource';
type Todo = Schema['Todo']['type'];
const client = generateClient<Schema>();
export default function MyComponent() { const [todos, setTodos] = useState<Todo[]>([]);
useEffect(() => { const sub = client.models.Todo.observeQuery().subscribe({ next: ({ items, isSynced }) => { setTodos([...items]); }, }); return () => sub.unsubscribe(); }, []);
return ( <ul> {todos.map((todo) => ( <li key={todo.id}>{todo.content}</li> ))} </ul> );}observeQueryはクラウド内で使用可能なすべてのデータをフェッチしてページネーションします。クラウドからデータが同期されている間、スナップショットには到着したすべてのアイテムとfalseのisSyncedステータスが含まれます。同期プロセスが完了すると、ローカルストア内のすべてのレコードとtrueのisSyncedステータスを含むスナップショットが発出されます。
トラブルシューティングリアルタイムイベントとモデルフィールドがない
期待するすべてのリアルタイムイベントとモデルフィールドが表示されない場合は、以下を確認してください。
認可
モデルの認可ルールはユーザーに適切な権限を付与する必要があります。
| 操作 | 認可 |
|---|---|
onCreate | read OR listen |
onUpdate | read OR listen |
onDelete | read OR listen |
observeQuery | read OR (listen AND list) |
認可ルールが正しい場合は、セッションが期待どおりに認証されていることを確認してください。
セレクションセットのパリティ
リアルタイム更新で表示されるすべてのフィールドは、それをトリガーするミューテーションのセレクションセットに存在する必要があります。ミューテーションは基本的にセレクションセットを介してフィールドを「提供」し、対応するサブスクリプションがそこから選択できます。
これに対処する1つの方法は、両方の操作に共通のセレクションセット変数を使用することです。例えば:
// セレクションセット `as const` を定義すると、型が// レスポンスオブジェクトに伝播することが保証されます。const selectionSet = ['title', 'author', 'posts.*'] as const;
const sub = client.models.Blog.observeQuery( filter: { id: { eq: 'blog-id' } }, selectionSet: [...selectionSet]).subscribe({ next(data) { handle(data.items) }});
// 更新は同じセレクションセットを使用し、必要なすべての// フィールドがサブスクライバーに提供されることを保証します。const { data } = await client.models.Blog.update({ id: 'blog-id', name: 'Updated Name'}, { selectionSet: [...selectionSet]});これは、Blogへのすべてのサブスクリプションが同じフィールドサブセットを必要とする場合に適切に機能します。複数のサブスクリプションが様々なセレクションセットを使用している場合は、すべてのBlogミューテーションがすべてのサブスクリプションからのフィールドのスーパーセットを含むことを確認する必要があります。
別の方法として、カスタムセレクションセット全体をスキップできます。任意のモデルの内部生成されたセレクションセットは、デフォルトで操作全体で同じです。トレードオフは、デフォルトのセレクションセットが関連モデルを除外することです。したがって、関連モデルが必要な場合は、遅延ロードするか、別にフェッチするクエリを構築する必要があります。
関連モデルのミューテーション
ミューテーションは関連モデルのリアルタイム更新をトリガーしません。これは、サブスクリプションがセレクションセットに関連モデルを含む場合でも当てはまります。例えば、特定のBlogを購読し、Postが追加または変更されたときに更新を表示したい場合、Blogにサブスクリプションを作成して「機能する」と仮定するのは魅力的です:
// `Blog`の詳細をいくつか取得しているが、主にセレクションセットを使用して// すべての関連投稿を取得していることに注意してください。const selectionSet = ['title', 'author', 'posts.*'] as const;
const sub = client.models.Blog.observeQuery( filter: { id: { eq: 'blog-id' } }, selectionSet: [...selectionSet]).subscribe({ next(data) { handle(data.items) }});しかし、Postレコードのミューテーションは関連Blogのリアルタイムイベントをトリガーしません。Postが追加されたときにBlogの更新が必要な場合は、関連するBlogレコードを手動で「タッチ」する必要があります。
async function addPostToBlog( post: Schema['Post']['createType'], blog: Schema['Blog']['type']) { // まずポストを作成します。 await client.models.Post.create({ ...post, blogId: blog.id });
// ブログを「タッチ」して、サブスクライバーに再レンダリングを通知します。 await client.models.Blog.update({ id: blog.id }, { // サブスクリプションが関連モデルフィールドを探している場合は // セレクションセットを含めることを忘れないでください! selectionSet: [...selectionSet] });}リアルタイムイベントサブスクリプションの設定
サブスクリプションは、特定のイベントが発生したときにサーバーがクライアントにデータを送信できる機能です。例えば、新しいレコードが作成、更新、または削除されたときのイベントを購読できます。サブスクリプションは、Amplifyデータスキーマの任意のa.model()で自動的に利用可能です。
import { generateClient } from 'aws-amplify/data';import type { Schema } from '../amplify/data/resource';
const client = generateClient<Schema>();
// Todoの作成を購読const createSub = client.models.Todo.onCreate().subscribe({ next: (data) => console.log(data), error: (error) => console.warn(error),});
// Todoの更新を購読const updateSub = client.models.Todo.onUpdate().subscribe({ next: (data) => console.log(data), error: (error) => console.warn(error),});
// Todoの削除を購読const deleteSub = client.models.Todo.onDelete().subscribe({ next: (data) => console.log(data), error: (error) => console.warn(error),});
// サブスクリプションからデータ更新の受け取りを停止createSub.unsubscribe();updateSub.unsubscribe();deleteSub.unsubscribe();サーバー側のサブスクリプションフィルターの設定
サブスクリプションは、サービス側のサブスクリプションフィルターを定義するオプショナルなfilter引数を受け取ります:
import { generateClient } from 'aws-amplify/data';import type { Schema } from '../amplify/data/resource';
const client = generateClient<Schema>();
const sub = client.models.Todo.onCreate({ filter: { content: { contains: 'groceries', }, },}).subscribe({ next: (data) => console.log(data), error: (error) => console.warn(error),});すべてのサブスクリプションイベントを取得する場合は、filterパラメータを指定しないでください。
サブスクリプション接続ステータス更新
アプリケーションが設定され、サブスクリプションを使用している状態で、サブスクリプションが最終的に確立されたときを知りたい場合があります。また、サブスクリプションが正常でない場合はユーザーに反映することができます。Hubローカルイベントシステムを通じて接続状態の変化を監視できます。
import { CONNECTION_STATE_CHANGE, ConnectionState } from 'aws-amplify/data';import { Hub } from 'aws-amplify/utils';
Hub.listen('api', (data: any) => { const { payload } = data; if (payload.event === CONNECTION_STATE_CHANGE) { const connectionState = payload.data.connectionState as ConnectionState; console.log(connectionState); }});サブスクリプション接続状態
Connected- 接続され、問題なく動作しています。ConnectedPendingDisconnect- 接続にアクティブなサブスクリプションがなく、切断しています。ConnectedPendingKeepAlive- 接続は開いていますが、予期されたキープアライブメッセージが失われています。ConnectedPendingNetwork- 接続は開いていますが、ネットワーク接続が中断されています。ネットワークが復旧すると、接続はトラフィック処理を継続します。Connecting- 接続を試みています。ConnectionDisrupted- 接続が中断され、ネットワークが利用可能です。ConnectionDisruptedPendingNetwork- 接続が中断され、ネットワーク接続が利用不可です。Disconnected- 接続にアクティブなサブスクリプションがなく、切断しています。
トラブルシューティング接続の問題の解決と自動再接続
アプリケーションとバックエンドサブスクリプション間の接続は、ネットワーク障害やデバイスがスリープモードに入るなど、様々な理由で中断される可能性があります。サブスクリプションは接続可能になると自動的に再接続します。
オフライン中、アプリケーションはメッセージを失い、再接続時に自動的に追いつくことはありません。ユースケースによっては、アプリがオンラインに戻ったときに追いつく処置を講じたい場合があります。
import { generateClient, CONNECTION_STATE_CHANGE, ConnectionState } from 'aws-amplify/data'import { Hub } from 'aws-amplify/utils'import { Schema } from '../amplify/data/resource';
const client = generateClient<Schema>()
const fetchRecentData = () => { const { data: allTodos } = await client.models.Todo.list();}
let priorConnectionState: ConnectionState;
Hub.listen("api", (data: any) => { const { payload } = data; if ( payload.event === CONNECTION_STATE_CHANGE ) {
if (priorConnectionState === ConnectionState.Connecting && payload.data.connectionState === ConnectionState.Connected) { fetchRecentData(); } priorConnectionState = payload.data.connectionState; }});
const createSub = client.models.Todo.onCreate().subscribe({ next: payload => // 受信メッセージを処理});
const updateSub = client.models.Todo.onUpdate().subscribe({ next: payload => // 受信メッセージを処理});
const deleteSub = client.models.Todo.onDelete().subscribe({ next: payload => // 受信メッセージを処理});
const cleanupSubscriptions = () => { createSub.unsubscribe(); updateSub.unsubscribe(); deleteSub.unsubscribe();}サブスクリプションから購読を解除
以下を実装してイベントのサブスクリプションから購読を解除することもできます:
// サブスクリプションからデータ更新の受け取りを停止sub.unsubscribe();まとめ
おめでとうございます!リアルタイムイベントの購読ガイドが完了しました。このガイドでは、リアルタイムイベントのサブスクリプションを設定し、必要に応じてこれらのサブスクリプションをフィルターしてキャンセルする方法を学びました。
次のステップ
推奨される次のステップには、データの情報アーキテクチャを構築およびカスタマイズし続けることが含まれます。このような作業に役立つリソースをいくつか紹介します: