

# Kit SDK de messagerie client de chat IVS : didacticiel React Native, partie 2 : messages et événements
<a name="chat-sdk-react-tutorial-messages-events"></a>

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

1. [S'abonner aux événements des messages de chat](#chat-react-messages-events-subscribe)

1. [Afficher les messages reçus](#chat-react-messages-events-show)

   1.  [Créer un composant de message](#chat-react-messages-create-component)

   1. [Reconnaître les messages envoyés par l'utilisateur actuel](#chat-react-messages-recognize)

   1. [Afficher une liste de messages de chat](#chat-react-messages-render-list)

1. [Effectuer des actions dans une salle de chat](#chat-react-messages-events-room-actions)

   1. [Envoi d'un message](#chat-react-room-actions-sending-message)

   1. [Supprimer un message](#chat-react-room-actions-deleting-message)

1. [Étapes suivantes](#chat-react-messages-events-next-steps)

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

## Prérequis
<a name="chat-react-messages-events-prerequisite"></a>

Assurez-vous d'avoir terminé la première partie de ce didacticiel relative aux [Salles de chat](chat-sdk-react-tutorial-chat-rooms.md).

## S'abonner aux événements des messages de chat
<a name="chat-react-messages-events-subscribe"></a>

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
<a name="chat-react-messages-events-show"></a>

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 :

1.  [Créer un composant de message](#chat-react-messages-create-component)

1. [Reconnaître les messages envoyés par l'utilisateur actuel](#chat-react-messages-recognize)

1. [Afficher une liste de messages de chat](#chat-react-messages-render-list)

### Créer un composant de message
<a name="chat-react-messages-create-component"></a>

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
<a name="chat-react-messages-recognize"></a>

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
<a name="chat-react-messages-render-list"></a>

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
<a name="chat-react-messages-events-room-actions"></a>

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](#chat-react-room-actions-sending-message) et [supprimer un message](#chat-react-room-actions-deleting-message).

### Envoi d'un message
<a name="chat-react-room-actions-sending-message"></a>

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](chat-sdk-react-tutorial-chat-rooms.md#chat-react-rooms-message-input) (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](#chat-react-messages-recognize).

**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
<a name="chat-react-room-actions-deleting-message"></a>

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](chat-sdk-react-tutorial-chat-rooms.md#chat-react-rooms-auth-server) (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](chat-sdk-react-tutorial-chat-rooms.md#chat-react-rooms-token-provider) (é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
<a name="chat-react-messages-events-next-steps"></a>

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