

# SDK de mensajería para clientes del chat de IVS, parte 2 del tutorial para React Native: mensajes y eventos
<a name="chat-sdk-react-tutorial-messages-events"></a>

Esta segunda (y última) parte del tutorial se divide en varias secciones:

1. [Suscribirse a los eventos de mensajes de chat](#chat-react-messages-events-subscribe)

1. [Mostrar los mensajes recibidos](#chat-react-messages-events-show)

   1.  [Crear un componente de mensaje](#chat-react-messages-create-component)

   1. [Identificar los mensajes que envía el usuario actual](#chat-react-messages-recognize)

   1. [Representar una lista de mensajes de chat](#chat-react-messages-render-list)

1. [Realizar acciones en una sala de chat](#chat-react-messages-events-room-actions)

   1. [Envío de un mensaje](#chat-react-room-actions-sending-message)

   1. [Eliminar mensajes](#chat-react-room-actions-deleting-message)

1. [Siguientes pasos](#chat-react-messages-events-next-steps)

**Nota**: En algunos casos, los ejemplos de código de JavaScript y TypeScript son idénticos, por lo cual se combinan.

## Requisito previo
<a name="chat-react-messages-events-prerequisite"></a>

Asegúrese de haber completado la parte 1 de este tutorial: [salas de chat](chat-sdk-react-tutorial-chat-rooms.md).

## Suscribirse a los eventos de mensajes de chat
<a name="chat-react-messages-events-subscribe"></a>

La instancia `ChatRoom` utiliza eventos para comunicarse cuando ocurren eventos en una sala de chat. Para comenzar a implementar la experiencia de chat, debe indicarles a los usuarios cuándo otros envían un mensaje en la sala a la que están conectados.

En este apartado, se suscribe a los eventos de mensajes de chat. Más adelante, le mostraremos cómo actualizar la lista de mensajes que crea, la cual se actualiza con cada mensaje o evento.

En su `App`, dentro del enlace `useEffect`, suscríbase a todos los eventos de mensajes:

**TypeScript/JavaScript**:

```
// App.tsx / App.jsx

useEffect(() => {
  // ...
  const unsubscribeOnMessageReceived = room.addListener('message', (message) => {});

  return () => {
    // ...
    unsubscribeOnMessageReceived();
  };
}, []);
```

## Mostrar los mensajes recibidos
<a name="chat-react-messages-events-show"></a>

La recepción de mensajes es una parte fundamental de la experiencia de chat. Con el SDK de JS de chat, puede configurar su código para recibir eventos de forma sencilla de otros usuarios conectados a una sala de chat.

Más adelante, le mostraremos cómo realizar acciones en una sala de chat que aproveche los componentes que crea aquí.

En su `App`, defina un estado denominado `messages` con un tipo de matriz `ChatMessage` denominado `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([]);

  //...
}
```

------

A continuación, en la función oyente de `message`, agregue `message` a la matriz `messages`:

**TypeScript/JavaScript**:

```
// App.tsx / App.jsx

// ...

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

// ...
```

A continuación, se detallan las tareas para mostrar los mensajes recibidos:

1.  [Crear un componente de mensaje](#chat-react-messages-create-component)

1. [Identificar los mensajes que envía el usuario actual](#chat-react-messages-recognize)

1. [Representar una lista de mensajes de chat](#chat-react-messages-render-list)

### Crear un componente de mensaje
<a name="chat-react-messages-create-component"></a>

El componente `Message` se encarga de presentar el contenido de los mensajes recibidos en la sala de chat. En esta sección, creará un componente de mensajes para representar mensajes de chat individuales en `App`.

En el directorio `src`, cree un archivo que denominará `Message`. Pase el tipo `ChatMessage` para este componente y pase la cadena `content` de las propiedades `ChatMessage` para mostrar el texto del mensaje recibido desde los oyentes de mensajes de la sala de chat. En el explorador de proyectos, diríjase a `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,
  },
});
```

------

**Sugerencia**: utilice este componente para almacenar las diferentes propiedades que desee representar en las filas de mensajes; por ejemplo, las URL de los avatares, los nombres de usuario y las marcas de tiempo de cuando se envió el mensaje.

### Identificar los mensajes que envía el usuario actual
<a name="chat-react-messages-recognize"></a>

Para identificar el mensaje que envía el usuario actual, modificamos el código y creamos un contexto de React para almacenar el `userId` de este usuario.

En el directorio `src`, cree un archivo que denominará `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;
```

------

Nota: Aquí utilizamos el enlace `useState` para almacenar el valor `userId`. Más adelante, puede utilizar `setUserId` para cambiar el contexto del usuario o para iniciar sesión.

Luego, sustituya el `userId` en el primer parámetro que se haya pasado al `tokenProvider`, utilizando el contexto creado anteriormente. Asegúrese de agregar la capacidad `SEND_MESSAGE` a su proveedor de tokens, como se especifica a continuación, ya que es necesaria para enviar mensajes.

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

  // ...
}
```

------

En el componente `Message`, utilice el `UserContext` que creó antes, declare la variable `isMine`, haga coincidir el `userId` del remitente con el `userId` del contexto y aplique diferentes estilos de mensajes para el usuario actual.

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

------

### Representar una lista de mensajes de chat
<a name="chat-react-messages-render-list"></a>

Ahora enumere los mensajes utilizando una `FlatList` y un componente `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>
);

// ...
```

------

Todas las partes del rompecabezas ya se encuentran en su lugar para que la `App` comience a representar los mensajes recibidos en la sala de chat. A continuación, aprenderá a realizar acciones en la sala de chat que aprovecha los componentes que creó.

## Realizar acciones en una sala de chat
<a name="chat-react-messages-events-room-actions"></a>

El envío de mensajes y las acciones de moderador en una sala de chat son algunas de las formas principales para interactuar con la sala de chat. Aquí aprenderá a utilizar varios objetos de solicitud de chat para realizar acciones comunes en Chatterbox, tales como enviar mensajes, eliminarlos y desconectar a otros usuarios.

Todas las acciones en la sala de chat siguen un patrón común: para cada acción que realice allí, hay un objeto de solicitud correspondiente. Para cada solicitud hay un objeto de respuesta correspondiente que recibe en la confirmación de la solicitud.

Siempre que los usuarios tengan las capacidades correctas cuando crea un token de chat, podrán realizar las acciones correspondientes de forma adecuada utilizando los objetos de solicitud para ver cuáles puede realizar en la sala de chat.

A continuación, le explicamos cómo [enviar un mensaje](#chat-react-room-actions-sending-message) y [eliminarlo](#chat-react-room-actions-deleting-message).

### Envío de un mensaje
<a name="chat-react-room-actions-sending-message"></a>

La clase `SendMessageRequest` permite enviar mensajes en una sala de chat. Aquí, modifique la `App` para enviar la solicitud del mensaje mediante el componente que creó en [Creación de una entrada de mensajes](chat-sdk-react-tutorial-chat-rooms.md#chat-react-rooms-message-input) (en la parte 1 de este tutorial).

Para empezar, defina una propiedad booleana nueva denominada `isSending` con el enlace `useState`. Utilice esta propiedad nueva para cambiar el estado deshabilitado del elemento `button` mediante la constante `isSendDisabled`. En el controlador de eventos del `SendButton`, borre el valor de `messageToSend` y configure `isSending` como verdadero.

*Dado que realizará una llamada a la API desde este botón, si agrega el booleano `isSending` ayudará a evitar que se produzcan varias llamadas a la API al mismo tiempo, ya que deshabilita las interacciones de los usuarios en `SendButton` hasta que se complete la solicitud.*

Nota: El envío de mensajes solo funciona si ha agregado la capacidad `SEND_MESSAGE` al proveedor de tokens, como se indica anteriormente en [Identificar los mensajes que envía el usuario actual](#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;

// ...
```

Prepare la solicitud mediante la creación de una instancia `SendMessageRequest` nueva, pasando el contenido del mensaje al constructor. Luego de configurar los estados `isSending` y `messageToSend`, llame al método `sendMessage`, el cual envía la solicitud a la sala de chat. Por último, borre la marca `isSending` al recibir la confirmación o la denegación de la solicitud.

**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);
  }
};

// ...
```

Pruebe Chatterbox: intente enviar un mensaje que redacte con `MessageBar`, y presione `SendButton`. Debería ver el mensaje representado dentro de `MessageList` que creó anteriormente.

### Eliminar mensajes
<a name="chat-react-room-actions-deleting-message"></a>

Para eliminar un mensaje de la sala de chat, debes tener la capacidad adecuada. Las capacidades se otorgan durante la inicialización del token de chat que utiliza para autenticarse en la sala de chat. Para los fines de esta sección, el formulario `ServerApp` de [Configuración de un servidor local de autenticación y autorización local](chat-sdk-react-tutorial-chat-rooms.md#chat-react-rooms-auth-server) (en la parte 1 de este tutorial) le permite especificar las capacidades del moderador. Lo tiene que realizar en la aplicación con el objeto `tokenProvider` que creó en [Creación de un proveedor de tokens](chat-sdk-react-tutorial-chat-rooms.md#chat-react-rooms-token-provider) (también en la parte 1).

Aquí puede modificar `Message` al agregar una función para eliminar el mensaje.

Primero, abra `App.tsx` y agregue la capacidad `DELETE_MESSAGE`. (`capabilities` es el segundo parámetro de la función `tokenProvider`).

Nota: Esta es la forma en que `ServerApp` informa a las API del chat de IVS de que el usuario asociado al token de chat resultante puede eliminar los mensajes de la sala de chat. En una situación real, probablemente se encontrará una lógica de backend más compleja para administrar las capacidades de los usuarios en la infraestructura de la aplicación del servidor.

**TypeScript/JavaScript**:

```
// App.tsx / App.jsx

// ...

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

// ...
```

En los siguientes pasos, actualizará `Message` para mostrar el botón de eliminación.

Defina una nueva función llamada `onDelete` que acepte una cadena como uno de los parámetros y devuelva `Promise`. Para el parámetro de cadena, pase el ID del mensaje del componente.

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

------

A continuación, actualice `renderItem` para que refleje los cambios más recientes en el componente `FlatList`.

Defina una función con el nombre `handleDeleteMessage` en `App` y pásela a la propiedad `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]);

// ...
```

------

Prepare una solicitud al crear una instancia nueva de `DeleteMessageRequest`, pasando el identificador del mensaje correspondiente al parámetro constructor, y llame a `deleteMessage` que acepta la solicitud preparada previamente:

------
#### [ 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);
};

// ...
```

------

Luego, actualice el estado `messages` para que refleje la lista nueva de mensajes que omite el mensaje que acaba de eliminar.

En el enlace `useEffect`, preste atención al evento `messageDelete` y actualice la matriz de estado `messages` al eliminar el mensaje con un identificador que coincida con el parámetro `message`.

Nota: Es posible que se genere el evento `messageDelete` para los mensajes que elimine el usuario actual o cualquier otro de la sala. Si lo administra en el controlador de eventos (en lugar de hacerlo junto a la solicitud `deleteMessage`) podrá unificar la administración de los mensajes eliminados.

**TypeScript/JavaScript**:

```
// App.tsx / App.jsx

// ...

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

return () => {
  // ...

  unsubscribeOnMessageDeleted();
};

// ...
```

Ahora puede eliminar usuarios de una sala de chat en la aplicación de chat.

## Siguientes pasos
<a name="chat-react-messages-events-next-steps"></a>

A modo de prueba, trate de implementar otras acciones en una sala, como desconectar a otro usuario.