Kit SDK de messagerie client de chat Amazon IVS : didacticiel React Native, partie 2 : messages et événements - Amazon IVS

Kit SDK de messagerie client de chat Amazon IVS : didacticiel React Native, partie 2 : messages et événements

Cette seconde et dernière partie du didacticiel est divisée en plusieurs sections :

Remarque : dans certains cas, les exemples de code pour JavaScript et TypeScript sont identiques et sont donc combinés.

Prérequis

Assurez-vous d'avoir terminé la première partie de ce didacticiel relative aux Salles de chat.

S'abonner aux événements des messages de chat

L'instance ChatRoom utilise des événements pour communiquer lorsque des événements se produisent dans une salle de chat. Pour commencer à mettre en œuvre l'expérience de chat, vous devez montrer à vos utilisateurs quand d'autres personnes envoient un message dans la salle à laquelle ils sont connectés.

Ici, vous vous abonnez aux événements des messages de chat. Plus tard, nous vous montrerons comment mettre à jour une liste de messages que vous créez, qui est mise à jour à chaque message/événement.

Dans votre App, dans le hook useEffect, abonnez-vous à tous les événements de message :

TypeScript/JavaScript :

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

Afficher les messages reçus

La réception de messages est au cœur de l'expérience de chat. À l'aide du kit SDK Chat JS, vous pouvez configurer votre code pour recevoir facilement les événements des autres utilisateurs connectés à une salle de chat.

Plus tard, nous vous montrerons comment effectuer des actions dans une salle de chat qui tirent parti des composants que vous créez ici.

Dans votre App, définissez un état nommé messages avec un type de tableau ChatMessage nommé 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([]); //... }

Ensuite, dans la fonction d'écouteur message, ajoutez message au tableau messages :

TypeScript/JavaScript :

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

Ci-dessous, nous passons en revue les tâches pour afficher les messages reçus :

Créer un composant de message

Le composant Message est chargé de rendre le contenu d'un message reçu par votre salle de chat. Dans cette section, vous créez un composant de messages pour afficher les messages de chat individuels dans l'App.

Dans le répertoire src, créez un fichier nommé Message. Transmettez le type ChatMessage de ce composant et transmettez la chaîne content provenant des propriétés ChatMessage pour afficher le texte du message reçu des écouteurs de messages de la salle de chat. Dans le navigateur de projets, accédez à 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, }, });

Conseil : utilisez ce composant pour stocker les différentes propriétés que vous souhaitez afficher dans les lignes de vos messages, par exemple, les URL des avatars, les noms d'utilisateur et les horodatages de l'envoi du message.

Reconnaître les messages envoyés par l'utilisateur actuel

Pour reconnaître le message envoyé par l'utilisateur actuel, nous modifions le code et créons un contexte React pour stocker le userId de l'utilisateur actuel.

Dans le répertoire src, créez un fichier nommé 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;

Remarque : ici, nous avons utilisé le hook useState pour stocker la valeur userId. Dorénavant, vous pourrez utiliser setUserId pour modifier le contexte de l'utilisateur ou à des fins de connexion.

Ensuite, remplacez userId dans le premier paramètre transmis à tokenProvider, en utilisant le contexte créé précédemment. Assurez-vous d'ajouter la capacité SEND_MESSAGE à votre fournisseur de jetons, comme indiqué ci-dessous ; elle est requise pour envoyer des messages.

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']), }), ); // ... }

Dans votre composant Message, utilisez le UserContext créé auparavant, déclarez la variable isMine, associez le userId de l'expéditeur au userId du contexte et appliquez différents styles de messages à l'utilisateur actuel.

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', }, });

Afficher une liste de messages de chat

Maintenant, répertoriez les messages à l'aide des composants FlatList et Message :

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> ); // ...

Toutes les pièces du puzzle sont maintenant en place pour que votre App commence à afficher les messages reçus par votre salle de chat. Continuez ci-dessous pour découvrir comment réaliser des actions dans une salle de chat qui tirent parti des composants que vous avez créés.

Effectuer des actions dans une salle de chat

L'envoi de messages et l'exécution d'actions de modérateur sont quelques-uns des principaux moyens d'interagir avec une salle de chat. Vous apprendrez ici comment utiliser divers objets de demande de chat pour effectuer des actions courantes dans Chatterbox, telles que l'envoi d'un message, la suppression d'un message et la déconnexion d'autres utilisateurs.

Toutes les actions d'une salle de chat suivent un schéma commun : à chaque action que vous effectuez dans une salle de chat, il existe un objet de demande correspondant. Pour chaque demande, il existe un objet de réponse correspondant que vous recevez lors de la confirmation de la demande.

Tant que vos utilisateurs disposent des capacités appropriées lorsque vous créez un jeton de chat, ils peuvent effectuer avec succès la ou les actions correspondantes à l'aide des objets de demande pour voir quelles demandes vous pouvez effectuer dans une salle de chat.

Ci-dessous, nous expliquons comment envoyer un message et supprimer un message.

Envoi d'un message

La classe SendMessageRequest permet d'envoyer des messages dans une salle de chat. Ici, vous modifiez votre App pour envoyer une demande de message à l'aide du composant que vous avez créé dans Créer une entrée de message (dans la première partie de ce didacticiel).

Pour commencer, définissez une nouvelle propriété booléenne nommée isSending avec le hook useState. Utilisez cette nouvelle propriété pour activer l'état désactivé de votre élément button à l'aide de la constante isSendDisabled. Dans le gestionnaire d'événements correspondant à votre SendButton, effacez la valeur de messageToSend et définissez isSending sur true (vrai).

Comme vous allez passer un appel d'API à partir de ce bouton, l'ajout du booléen isSending permet d'éviter que plusieurs appels d'API ne se produisent en même temps, en désactivant les interactions utilisateur sur votre SendButton jusqu'à ce que la demande soit complète.

Remarque : l'envoi de messages ne fonctionne que si vous avez ajouté la capacité SEND_MESSAGE à votre fournisseur de jetons, comme indiqué ci-dessus dans la rubrique Reconnaître les messages envoyés par l'utilisateur actuel.

TypeScript/JavaScript :

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

Préparez la demande en créant une instance SendMessageRequest et en transmettant le contenu du message au constructeur. Après avoir défini les états isSending et messageToSend, appelez la méthode sendMessage qui envoie la demande à la salle de chat. Enfin, effacez l'indicateur isSending lors de la réception de la confirmation ou du rejet de la demande.

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); } }; // ...

Essayez Chatterbox : essayez d'envoyer un message en rédigeant un message avec votre MessageBar et en appuyant sur votre SendButton. Vous devriez voir le message que vous avez envoyé s'afficher dans la MessageList que vous avez créée précédemment.

Supprimer un message

Pour supprimer un message d'une salle de chat, vous devez disposer de la capacité appropriée. Les capacités sont accordées lors de l'initialisation du jeton de chat que vous utilisez pour vous authentifier dans une salle de chat. Pour les besoins de cette section, le formulaire ServerApp de la section Configurer un serveur d'authentification/d'autorisation local (dans la partie 1 de ce didacticiel) vous permet de spécifier les capacités des modérateurs. Cela se fait dans votre application à l'aide de l'objet tokenProvider que vous avez créé dans la section Créer un fournisseur de jetons (également dans la partie 1).

Vous pouvez ici modifier votre Message en ajoutant une fonction pour supprimer le message.

Tout d'abord, ouvrez le App.tsx et ajoutez la fonctionnalité DELETE_MESSAGE. (capabilities est le deuxième paramètre de votre fonction tokenProvider.)

Remarque : c'est de cette manière que votre ServerApp informe les API IVS Chat que l'utilisateur associé au jeton de chat obtenu peut supprimer des messages dans une salle de chat. Dans une situation réelle, vous aurez probablement une logique backend plus complexe pour gérer les capacités des utilisateurs dans l'infrastructure de votre application serveur.

TypeScript/JavaScript :

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

Au cours des étapes suivantes, vous mettrez à jour votre Message pour afficher un bouton de suppression.

Définissez une nouvelle fonction appelée onDelete qui accepte une chaîne comme paramètre et renvoie Promise. Pour le paramètre de chaîne, transmettez l'ID du message de votre composant.

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', }, });

Ensuite, mettez à jour votre composant renderItem pour qu'il reflète les dernières modifications apportées à votre composant FlatList.

Dans App, définissez une fonction nommée handleDeleteMessage et transmettez-la à la propriété 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]); // ...

Préparez une demande en créant une instance de DeleteMessageRequest, en transmettant l'ID de message correspondant au paramètre du constructeur et en appelant deleteMessage qui accepte la demande préparée ci-dessus :

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); }; // ...

Ensuite, vous mettez à jour votre état messages pour refléter une nouvelle liste de messages qui omet le message que vous venez de supprimer.

Dans le hook useEffect, écoutez l'événement messageDelete et mettez à jour votre tableau d'états messages en supprimant le message dont l'ID correspond au paramètre message.

Remarque : l'événement messageDelete peut être déclenché en cas de suppression de messages par l'utilisateur actuel ou par tout autre utilisateur présent dans la salle. Le gérer dans le gestionnaire d'événements (plutôt qu'à côté de la demande deleteMessage) vous permet d'unifier la gestion des messages de suppression.

TypeScript/JavaScript :

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

Vous pouvez désormais supprimer des utilisateurs d'une salle de chat dans votre application de chat.

Étapes suivantes

À titre expérimental, essayez de mettre en œuvre d'autres actions dans une salle, par exemple la déconnexion d'un autre utilisateur.