Client-Messaging-SDK für IVS Chat: Tutorial für React Native, Teil 2: Nachrichten und Ereignisse - Amazon IVS

Client-Messaging-SDK für IVS Chat: Tutorial für React Native, Teil 2: Nachrichten und Ereignisse

Der vorliegende zweite (und letzte) Teil des Tutorials ist in mehrere Abschnitte unterteilt:

Hinweis: In einigen Fällen sind die Codebeispiele für JavaScript und TypeScript identisch, daher werden sie kombiniert.

Voraussetzung

Absolvieren Sie unbedingt Teil 1 dieses Tutorials: Chatrooms.

Abonnieren von Chat-Nachrichtenereignissen

Mithilfe von Ereignissen informiert die Instance ChatRoom darüber, wann Ereignisse in einem Chatroom stattfinden. Um mit der Chatimplementierung zu beginnen, müssen Sie die Benutzer darüber informieren, wenn andere in dem Chatroom, mit dem sie verbunden sind, eine Nachricht senden.

An dieser Stelle abonnieren Sie Chat-Nachrichtenereignisse. Später zeigen wir Ihnen, wie Sie eine selbst erstellte Nachrichtenliste aktualisieren, die bei jeder Nachricht und jedem Ereignis aktualisiert wird.

Abonnieren Sie in Ihrer App im Hook useEffect alle Nachrichtenereignisse:

TypeScript/JavaScript:

// App.tsx / App.jsx useEffect(() => { // ... const unsubscribeOnMessageReceived = room.addListener('message', (message) => {}); return () => { // ... unsubscribeOnMessageReceived(); }; }, []);

Anzeigen empfangener Nachrichten

Das Empfangen von Nachrichten ist ein zentraler Bestandteil beim Chatten. Mit dem Chat JS SDK können Sie den Code so einrichten, dass Ereignisse von anderen Benutzern, die mit einem Chatroom verbunden sind, problemlos empfangen werden.

Später zeigen wir Ihnen, wie Sie Aktionen in einem Chatroom ausführen, die die hier erstellten Komponenten nutzen.

Definieren Sie in Ihrer App einen Status namens messages mit einem ChatMessage-Array-Typ namens messages:

TypeScript
// App.tsx // ... import { ChatRoom, ChatMessage, ConnectionState } from 'amazon-ivs-chat-messaging'; export default function App() { const [messages, setMessages] = useState<ChatMessage[]>([]); //... }
JavaScript
// App.jsx // ... import { ChatRoom, ConnectionState } from 'amazon-ivs-chat-messaging'; export default function App() { const [messages, setMessages] = useState([]); //... }

Als Nächstes fügen Sie in der Listener-Funktion message die Zeichenfolge message an das Array messages an:

TypeScript/JavaScript:

// App.tsx / App.jsx // ... const unsubscribeOnMessageReceived = room.addListener('message', (message) => { setMessages((msgs) => [...msgs, message]); }); // ...

Im Folgenden gehen wir die Aufgaben zum Anzeigen empfangener Nachrichten Schritt für Schritt durch:

Erstellen einer Nachrichtenkomponente

Die Komponente Message rendert den Inhalt einer Nachricht, die im Chatroom empfangen wurde. In diesem Abschnitt erstellen Sie eine Nachrichtenkomponente zum Rendern einzelner Chatnachrichten in der App.

Erstellen Sie im Verzeichnis src eine neue Datei und geben Sie ihr den Namen Message. Übergeben Sie den ChatMessage-Typ für diese Komponente und die Zeichenfolge content aus den ChatMessage-Eigenschaften, um den Nachrichtentext anzuzeigen, der von Listenern für Chatroom-Nachrichten empfangen wurde. Wechseln Sie im Projektnavigator zu Message.

TypeScript
// Message.tsx import React from 'react'; import { View, Text, StyleSheet } from 'react-native'; import { ChatMessage } from 'amazon-ivs-chat-messaging'; type Props = { message: ChatMessage; } export const Message = ({ message }: Props) => { return ( <View style={styles.root}> <Text>{message.sender.userId}</Text> <Text style={styles.textContent}>{message.content}</Text> </View> ); }; const styles = StyleSheet.create({ root: { backgroundColor: 'silver', padding: 6, borderRadius: 10, marginHorizontal: 12, marginVertical: 5, marginRight: 50, }, textContent: { fontSize: 17, fontWeight: '500', flexShrink: 1, }, });
JavaScript
// Message.jsx import React from 'react'; import { View, Text, StyleSheet } from 'react-native'; export const Message = ({ message }) => { return ( <View style={styles.root}> <Text>{message.sender.userId}</Text> <Text style={styles.textContent}>{message.content}</Text> </View> ); }; const styles = StyleSheet.create({ root: { backgroundColor: 'silver', padding: 6, borderRadius: 10, marginHorizontal: 12, marginVertical: 5, marginRight: 50, }, textContent: { fontSize: 17, fontWeight: '500', flexShrink: 1, }, });

Tipp: Mit dieser Komponente können Sie verschiedene Eigenschaften speichern, die in den Nachrichtenzeilen gerendert werden sollen, z. B. Avatar-URLs, Benutzernamen und Zeitstempel für den Nachrichtenversand.

Erkennen von Nachrichten, die vom aktuellen Benutzer gesendet wurden

Um die vom aktuellen Benutzer gesendete Nachricht zu erkennen, ändern wir den Code und erstellen einen React-Kontext zum Speichern der userId des aktuellen Benutzers.

Erstellen Sie im Verzeichnis src eine neue Datei und geben Sie ihr den Namen UserContext:

TypeScript
// UserContext.tsx import React from 'react'; const UserContext = React.createContext<string | undefined>(undefined); export const useUserContext = () => { const context = React.useContext(UserContext); if (context === undefined) { throw new Error('useUserContext must be within UserProvider'); } return context; }; export const UserProvider = UserContext.Provider;
JavaScript
// UserContext.jsx import React from 'react'; const UserContext = React.createContext(undefined); export const useUserContext = () => { const context = React.useContext(UserContext); if (context === undefined) { throw new Error('useUserContext must be within UserProvider'); } return context; }; export const UserProvider = UserContext.Provider;

Hinweis: Hier haben wir den Wert userId mit dem Hook useState gespeichert. Künftig können Sie zum Ändern des Benutzerkontexts oder zum Anmelden setUserId verwenden.

Ersetzen Sie als Nächstes userId im ersten Parameter, der an tokenProvider übergeben wurde. Verwenden Sie dabei den zuvor erstellten Kontext. Stellen Sie sicher, dass Sie Ihrem Token-Anbieter die SEND_MESSAGE-Funktion hinzufügen, wie unten angegeben. Sie ist erforderlich, um Nachrichten zu senden:

TypeScript
// App.tsx // ... import { useUserContext } from './UserContext'; // ... export default function App() { const [messages, setMessages] = useState<ChatMessage[]>([]); const userId = useUserContext(); const [room] = useState( () => new ChatRoom({ regionOrUrl: process.env.REGION, tokenProvider: () => tokenProvider(userId, ['SEND_MESSAGE']), }), ); // ... }
JavaScript
// App.jsx // ... import { useUserContext } from './UserContext'; // ... export default function App() { const [messages, setMessages] = useState([]); const userId = useUserContext(); const [room] = useState( () => new ChatRoom({ regionOrUrl: process.env.REGION, tokenProvider: () => tokenProvider(userId, ['SEND_MESSAGE']), }), ); // ... }

Verwenden Sie in Ihrer Message-Komponente den zuvor erstellten UserContext, deklarieren Sie die Variable isMine, ordnen Sie die userId des Absenders der userId aus dem Kontext zu und wenden Sie verschiedene Nachrichtenstile für den aktuellen Benutzer an.

TypeScript
// Message.tsx import React from 'react'; import { View, Text, StyleSheet } from 'react-native'; import { ChatMessage } from 'amazon-ivs-chat-messaging'; import { useUserContext } from './UserContext'; type Props = { message: ChatMessage; } export const Message = ({ message }: Props) => { const userId = useUserContext(); const isMine = message.sender.userId === userId; return ( <View style={[styles.root, isMine && styles.mine]}> {!isMine && <Text>{message.sender.userId}</Text>} <Text style={styles.textContent}>{message.content}</Text> </View> ); }; const styles = StyleSheet.create({ root: { backgroundColor: 'silver', padding: 6, borderRadius: 10, marginHorizontal: 12, marginVertical: 5, marginRight: 50, }, textContent: { fontSize: 17, fontWeight: '500', flexShrink: 1, }, mine: { flexDirection: 'row-reverse', backgroundColor: 'lightblue', }, });
JavaScript
// Message.jsx import React from 'react'; import { View, Text, StyleSheet } from 'react-native'; import { ChatMessage } from 'amazon-ivs-chat-messaging'; import { useUserContext } from './UserContext'; export const Message = ({ message }) => { const userId = useUserContext(); const isMine = message.sender.userId === userId; return ( <View style={[styles.root, isMine && styles.mine]}> {!isMine && <Text>{message.sender.userId}</Text>} <Text style={styles.textContent}>{message.content}</Text> </View> ); }; const styles = StyleSheet.create({ root: { backgroundColor: 'silver', padding: 6, borderRadius: 10, marginHorizontal: 12, marginVertical: 5, marginRight: 50, }, textContent: { fontSize: 17, fontWeight: '500', flexShrink: 1, }, mine: { flexDirection: 'row-reverse', backgroundColor: 'lightblue', }, });

Rendern einer Liste von Chatnachrichten

Listen Sie jetzt Nachrichten auf, indem Sie FlatList und eine Message-Komponente verwenden:

TypeScript
// App.tsx // ... const renderItem = useCallback<ListRenderItem<ChatMessage>>(({ item }) => { return ( <Message key={item.id} message={item} /> ); }, []); return ( <SafeAreaView style={styles.root}> <Text>Connection State: {connectionState}</Text> <FlatList inverted data={messages} renderItem={renderItem} /> <View style={styles.messageBar}> <MessageInput value={messageToSend} onMessageChange={setMessageToSend} /> <SendButton disabled={isSendDisabled} onPress={onMessageSend} /> </View> </SafeAreaView> ); // ...
JavaScript
// App.jsx // ... const renderItem = useCallback(({ item }) => { return ( <Message key={item.id} message={item} /> ); }, []); return ( <SafeAreaView style={styles.root}> <Text>Connection State: {connectionState}</Text> <FlatList inverted data={messages} renderItem={renderItem} /> <View style={styles.messageBar}> <MessageInput value={messageToSend} onMessageChange={setMessageToSend} /> <SendButton disabled={isSendDisabled} onPress={onMessageSend} /> </View> </SafeAreaView> ); // ...

Alle Puzzleteile sind jetzt vorhanden, damit Ihre App Nachrichten rendern kann, die aus dem Chatroom empfangen wurden. Nachfolgend erfahren Sie, wie Sie in einem Chatroom Aktionen ausführen, die die von Ihnen erstellten Komponenten nutzen.

Durchführen von Aktionen in einem Chatroom

Das Senden von Nachrichten und das Durchführen von Moderatorenaktionen sind einige der wichtigsten Formen der Interaktion. Hier erfahren Sie, wie Sie mithilfe verschiedener Chat-Anfrage Objekte allgemeine Aktionen in Chatterbox durchführen. Dazu gehören das Senden und Löschen von Nachrichten sowie das Trennen der Verbindung anderer Benutzer.

Alle Aktionen in einem Chatroom folgen einem gemeinsamen Muster: Für jede Aktion, die in einem Chatroom durchgeführt wird, gibt es ein entsprechendes Anforderungsobjekt. Für jede Anforderung gibt es ein entsprechendes Antwortobjekt, das bei Bestätigung der Anforderung empfangen wird.

Solange den Benutzern beim Erstellen eines Chat-Tokens die richtigen Fähigkeiten erteilt werden, können sie die entsprechenden Aktionen erfolgreich durchführen. Mithilfe der Anforderungsobjekte lässt sich feststellen, welche Anforderungen in einem Chatroom durchgeführt werden können.

Nachfolgend erklären wir das Senden einer Nachricht und das Löschen einer Nachricht.

Senden einer Nachricht

Die Klasse SendMessageRequest ermöglicht das Senden von Nachrichten in einem Chatroom. Hier ändern Sie Ihre App, um mit der Komponente, die Sie unter Erstellen einer Nachrichteneingabe (in Teil 1 dieses Tutorials) erstellt haben, eine Nachrichtenanforderung zu senden.

Definieren Sie zunächst eine neue boolesche Eigenschaft namens isSending mit dem Hook useState. Schalten Sie mithilfe dieser neuen Eigenschaft den deaktivierten Status des button-Elements um. Verwenden Sie dabei die Konstante isSendDisabled. Löschen Sie im Event-Handler für SendButton den Wert für messageToSend und stellen Sie isSending auf „true“ ein.

Da über diese Schaltfläche ein API-Aufruf getätigt wird, verhindert das Hinzufügen des booleschen Werts isSending, dass mehrere API-Aufrufe gleichzeitig ausgeführt werden. Dazu werden Benutzerinteraktionen für SendButton deaktiviert, bis die Anforderung abgeschlossen ist.

Hinweis: Das Senden von Nachrichten funktioniert nur, wenn Sie Ihrem Token-Anbieter die SEND_MESSAGE-Funktion hinzugefügt haben, wie oben unter Erkennen von Nachrichten, die vom aktuellen Benutzer gesendet wurden, beschrieben.

TypeScript/JavaScript:

// App.tsx / App.jsx // ... const [isSending, setIsSending] = useState(false); // ... const onMessageSend = () => { setIsSending(true); setMessageToSend(''); }; // ... const isSendDisabled = connectionState !== 'connected' || isSending; // ...

Bereiten Sie die Anforderung vor, indem Sie eine neue SendMessageRequest-Instance erstellen und den Nachrichteninhalt an den Konstruktor übergeben. Rufen Sie nach dem Festlegen des Status von isSending und messageToSend die Methode sendMessage auf, die die Anforderung an den Chatroom sendet. Löschen Sie abschließend das Flag isSending, sobald Sie eine Bestätigung oder Ablehnung der Anforderung erhalten haben.

TypeScript/JavaScript:

// App.tsx / App.jsx // ... import { ChatRoom, ConnectionState, SendMessageRequest } from 'amazon-ivs-chat-messaging' // ... const onMessageSend = async () => { const request = new SendMessageRequest(messageToSend); setIsSending(true); setMessageToSend(''); try { const response = await room.sendMessage(request); } catch (e) { console.log(e); // handle the chat error here... } finally { setIsSending(false); } }; // ...

Führen Sie Chatterbox aus: Senden Sie eine Nachricht, indem Sie eine Nachricht mit MessageBar verfassen und auf SendButton tippen. Die gesendete Nachricht sollte in der MessageList, die Sie zuvor erstellt haben, gerendert werden.

Löschen einer Nachricht

Um eine Nachricht aus einem Chatroom zu löschen, benötigen Sie die entsprechende Fähigkeit. Fähigkeiten werden bei der Initialisierung des Chat-Tokens gewährt, das Sie bei der Authentifizierung in einem Chatroom verwenden. Für die Zwecke dieses Abschnitts können Sie in der ServerApp aus Einrichten eines lokalen Authentifizierungs-/Autorisierungsservers (in Teil 1 dieses Tutorials) die Moderatorfähigkeiten festlegen. Dies geschieht in der App mithilfe des Objekts tokenProvider, das Sie unter Erstellen eines Token-Anbieters (ebenfalls in Teil 1) erstellt haben.

Hier ändern Sie Ihre Message, indem Sie eine Funktion zum Löschen der Nachricht hinzufügen.

Öffnen Sie zunächst App.tsx und fügen Sie die Fähigkeit DELETE_MESSAGE hinzu. (capabilities ist der zweite Parameter der Funktion tokenProvider.)

Hinweis: Auf diese Weise informiert die ServerApp die IVS-Chat-APIs darüber, dass der Benutzer, der mit dem resultierenden Chat-Token verknüpft wird, Nachrichten in einem Chatroom löschen kann. In einer realen Umgebung wird die Backend-Logik zur Verwaltung der Benutzerfähigkeiten in der Infrastruktur Ihrer Server-App wahrscheinlich komplexer sein.

TypeScript/JavaScript:

// App.tsx / App.jsx // ... const [room] = useState(() => new ChatRoom({ regionOrUrl: process.env.REGION, tokenProvider: () => tokenProvider(userId, ['SEND_MESSAGE', 'DELETE_MESSAGE']), }), ); // ...

In den nächsten Schritten aktualisieren Sie Ihre Message, um eine Schaltfläche zum Löschen anzuzeigen.

Definieren Sie eine neue Funktion namens onDelete, die eine Zeichenfolge als einen möglichen Parameter akzeptiert und Promise zurückgibt. Übergeben Sie als Zeichenfolgenparameter die ID der Komponentennachricht.

TypeScript
// Message.tsx import React from 'react'; import { View, Text, StyleSheet } from 'react-native'; import { ChatMessage } from 'amazon-ivs-chat-messaging'; import { useUserContext } from './UserContext'; export type Props = { message: ChatMessage; onDelete(id: string): Promise<void>; }; export const Message = ({ message, onDelete }: Props) => { const userId = useUserContext(); const isMine = message.sender.userId === userId; const handleDelete = () => onDelete(message.id); return ( <View style={[styles.root, isMine && styles.mine]}> {!isMine && <Text>{message.sender.userId}</Text>} <View style={styles.content}> <Text style={styles.textContent}>{message.content}</Text> <TouchableOpacity onPress={handleDelete}> <Text>Delete<Text/> </TouchableOpacity> </View> </View> ); }; const styles = StyleSheet.create({ root: { backgroundColor: 'silver', padding: 6, borderRadius: 10, marginHorizontal: 12, marginVertical: 5, marginRight: 50, }, content: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', }, textContent: { fontSize: 17, fontWeight: '500', flexShrink: 1, }, mine: { flexDirection: 'row-reverse', backgroundColor: 'lightblue', }, });
JavaScript
// Message.jsx import React from 'react'; import { View, Text, StyleSheet } from 'react-native'; import { ChatMessage } from 'amazon-ivs-chat-messaging'; import { useUserContext } from './UserContext'; export const Message = ({ message, onDelete }) => { const userId = useUserContext(); const isMine = message.sender.userId === userId; const handleDelete = () => onDelete(message.id); return ( <View style={[styles.root, isMine && styles.mine]}> {!isMine && <Text>{message.sender.userId}</Text>} <View style={styles.content}> <Text style={styles.textContent}>{message.content}</Text> <TouchableOpacity onPress={handleDelete}> <Text>Delete<Text/> </TouchableOpacity> </View> </View> ); }; const styles = StyleSheet.create({ root: { backgroundColor: 'silver', padding: 6, borderRadius: 10, marginHorizontal: 12, marginVertical: 5, marginRight: 50, }, content: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', }, textContent: { fontSize: 17, fontWeight: '500', flexShrink: 1, }, mine: { flexDirection: 'row-reverse', backgroundColor: 'lightblue', }, });

Als Nächstes aktualisieren Sie die renderItem, damit die neuesten Änderungen an Ihrer FlatList-Komponente wiedergegeben werden.

Definieren Sie in App eine Funktion namens handleDeleteMessage und übergeben Sie sie an die Eigenschaft MessageList onDelete:

TypeScript
// App.tsx // ... const handleDeleteMessage = async (id: string) => {}; const renderItem = useCallback<ListRenderItem<ChatMessage>>(({ item }) => { return ( <Message key={item.id} message={item} onDelete={handleDeleteMessage} /> ); }, [handleDeleteMessage]); // ...
JavaScript
// App.jsx // ... const handleDeleteMessage = async (id) => {}; const renderItem = useCallback(({ item }) => { return ( <Message key={item.id} message={item} onDelete={handleDeleteMessage} /> ); }, [handleDeleteMessage]); // ...

Bereiten Sie eine Anforderung vor, indem Sie eine neue Instance von DeleteMessageRequest erstellen und die entsprechende Nachrichten-ID an den Konstruktorparameter übergeben. Rufen Sie dann den Befehl deleteMessage auf, der die oben vorbereitete Anforderung akzeptiert:

TypeScript
// App.tsx // ... const handleDeleteMessage = async (id: string) => { const request = new DeleteMessageRequest(id); await room.deleteMessage(request); }; // ...
JavaScript
// App.jsx // ... const handleDeleteMessage = async (id) => { const request = new DeleteMessageRequest(id); await room.deleteMessage(request); }; // ...

Als Nächstes aktualisieren Sie den Status messages, damit eine neue Liste von Nachrichten – ohne die gerade gelöschte Nachricht – angezeigt wird.

Warten Sie im Hook useEffect auf das Ereignis messageDelete und aktualisieren Sie das Status-Array messages, indem Sie die Nachricht mit einer zum Parameter message passenden ID löschen.

Hinweis: Das Ereignis messageDelete kann ausgelöst werden, wenn Nachrichten vom aktuellen Benutzer oder von anderen Benutzern im Chatroom gelöscht wurden. Wenn Sie es im Ereignishandler verarbeiten (statt neben der Anforderung deleteMessage), können Sie das Löschen von Nachrichten vereinheitlichen.

TypeScript/JavaScript:

// App.tsx / App.jsx // ... const unsubscribeOnMessageDeleted = room.addListener('messageDelete', (deleteMessageEvent) => { setMessages((prev) => prev.filter((message) => message.id !== deleteMessageEvent.id)); }); return () => { // ... unsubscribeOnMessageDeleted(); }; // ...

Sie können jetzt Benutzer aus einem Chatroom in Ihrer Chat-App löschen.

Nächste Schritte

Versuchen Sie als Experiment, andere Aktionen in einem Chatroom zu implementieren, z. B. das Trennen der Verbindung eines anderen Benutzers.