

# SDK de Mensagens para Clientes do Chat do IVS: Tutorial do React Native, parte 2: mensagens e eventos
<a name="chat-sdk-react-tutorial-messages-events"></a>

Esta segunda e última parte do tutorial é dividida em várias seções:

1. [Inscreva-se em eventos de mensagens de chat](#chat-react-messages-events-subscribe)

1. [Exibir mensagens recebidas](#chat-react-messages-events-show)

   1.  [Criação de um componente de mensagem](#chat-react-messages-create-component)

   1. [Reconhecimento das mensagens enviadas pelo usuário atual](#chat-react-messages-recognize)

   1. [Renderização de uma lista de mensagens de chat](#chat-react-messages-render-list)

1. [Executar ações em uma sala de chat](#chat-react-messages-events-room-actions)

   1. [Enviar uma mensagem](#chat-react-room-actions-sending-message)

   1. [Excluir mensagem](#chat-react-room-actions-deleting-message)

1. [Próximas etapas](#chat-react-messages-events-next-steps)

**Observação**: em alguns casos, os exemplos de código para JavaScript e TypeScript são idênticos, então eles são combinados.

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

Certifique-se de ter concluído a parte 1 deste tutorial, [salas de chat](chat-sdk-react-tutorial-chat-rooms.md).

## Inscreva-se em eventos de mensagens de chat
<a name="chat-react-messages-events-subscribe"></a>

A instância `ChatRoom` usa eventos para se comunicar, quando os eventos ocorrem em uma sala de chat. Para começar a implementar a experiência de chat, você precisa mostrar aos usuários quando as outras pessoas enviam uma mensagem na sala à qual estão conectados.

Aqui, você se inscreve em eventos de mensagens de chat Posteriormente, mostraremos como atualizar uma lista de mensagens que você criou e é atualizada com cada mensagem/evento.

Em seu `App`, dentro do hook `useEffect`, inscreva-se em todos os eventos de mensagens:

**TypeScript/JavaScript**:

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

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

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

## Exibir mensagens recebidas
<a name="chat-react-messages-events-show"></a>

Receber mensagens é parte essencial da experiência de chat. Usando o SDK do Chat JS, é possível configurar seu código para receber facilmente eventos de outros usuários conectados a uma sala de chat.

Posteriormente, mostraremos como realizar ações em uma sala de chat que utilizam os componentes criados por você aqui.

Em sua `App`, defina um estado chamado `messages`, com um tipo de matriz `ChatMessage` chamado `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([]);

  //...
}
```

------

Em seguida, na função de receptor da `message`, acrescente `message` à matriz `messages`:

**TypeScript/JavaScript**:

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

// ...

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

// ...
```

Abaixo, analisamos as tarefas para mostrar as mensagens recebidas:

1.  [Criação de um componente de mensagem](#chat-react-messages-create-component)

1. [Reconhecimento das mensagens enviadas pelo usuário atual](#chat-react-messages-recognize)

1. [Renderização de uma lista de mensagens de chat](#chat-react-messages-render-list)

### Criação de um componente de mensagem
<a name="chat-react-messages-create-component"></a>

O componente `Message` é responsável por renderizar o conteúdo de uma mensagem recebida pela sua sala de chat. Nesta seção, você cria um componente de mensagens para renderizar mensagens de chat individuais na `App`.

Crie um novo arquivo no diretório `src` e atribua a ele o nome `Message`. Passe o tipo `ChatMessage` para esse componente e, em seguida, passe a string `content` das propriedades de `ChatMessage` para exibir o texto da mensagem recebida dos receptores de mensagens da sala de chat. No Project Navigator, acesse `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,
  },
});
```

------

**Dica**: use este componente para armazenar propriedades diferentes que você deseja renderizar em suas linhas de mensagens; por exemplo, URLs de avatar, nomes de usuário e carimbos de data e hora de quando a mensagem foi enviada.

### Reconhecimento das mensagens enviadas pelo usuário atual
<a name="chat-react-messages-recognize"></a>

Para reconhecer a mensagem enviada pelo usuário atual, modificamos o código e criamos um contexto do React para armazenar o `userId` do usuário atual.

Crie um novo arquivo no diretório `src` e atribua a ele o nome `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;
```

------

Observação: aqui usamos o hook `useState` para armazenar o valor `userId`. No futuro, será possível usar `setUserId` para alterar o contexto do usuário ou para fins de login.

Em seguida, substitua `userId` no primeiro parâmetro passado para `tokenProvider` usando o contexto criado anteriormente. Adicione o recurso `SEND_MESSAGE` ao seu provedor de token, conforme especificado abaixo; é necessário enviar mensagens:

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

  // ...
}
```

------

Em seu componente `Message`, use o `UserContext` criado antes, declare a variável `isMine`, corresponda o `userId` do remetente com o `userId` do contexto e aplique estilos diferentes de mensagens para o usuário atual.

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

------

### Renderização de uma lista de mensagens de chat
<a name="chat-react-messages-render-list"></a>

Agora, liste as mensagens usando um componente `FlatList` e `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 as peças do quebra-cabeça estão prontas para que sua `App` comece a renderizar as mensagens recebidas pela sua sala de chat. Continue abaixo para ver como realizar ações em uma sala de chat que aproveitem os componentes que você criou.

## Executar ações em uma sala de chat
<a name="chat-react-messages-events-room-actions"></a>

Enviar mensagens e realizar ações de moderador são algumas das principais formas de interagir com uma sala de chat. Aqui, você aprenderá como usar vários objetos de solicitação de chat para realizar ações comuns no Chatterbox, como enviar uma mensagem, excluir uma mensagem e desconectar outros usuários.

Todas as ações em uma sala de chat seguem um padrão comum: para cada ação executada em uma sala de chat, há um objeto de solicitação correspondente. Para cada solicitação, há um objeto de resposta correspondente que você recebe na confirmação da solicitação.

Uma vez que seus usuários recebam as permissões corretas quando você criar um token de chat, eles poderão realizar com êxito as ações correspondentes usando os objetos de solicitação para ver quais solicitações são possíveis de serem realizadas em uma sala de chat.

Abaixo, explicamos como [enviar uma mensagem](#chat-react-room-actions-sending-message) e [excluir uma mensagem](#chat-react-room-actions-deleting-message).

### Enviar uma mensagem
<a name="chat-react-room-actions-sending-message"></a>

A classe `SendMessageRequest` permite o envio de mensagens em uma sala de chat. Aqui, você modifica sua `App` para enviar uma solicitação de mensagem usando o componente que criou em [Criar uma entrada de mensagem](chat-sdk-react-tutorial-chat-rooms.md#chat-react-rooms-message-input) (na parte 1 deste tutorial).

Para começar, defina uma nova propriedade booleana chamada de `isSending` com o hook `useState`. Use essa nova propriedade para alternar o estado desabilitado do seu elemento `button` usando a constante `isSendDisabled`. No manipulador de eventos do seu `SendButton`, limpe o valor de `messageToSend` e defina `isSending` como verdadeiro.

*Como você fará uma chamada de API a partir desse botão, adicionar o booleano `isSending` ajuda a evitar que várias chamadas de API ocorram ao mesmo tempo, desativando as interações do usuário no seu `SendButton` até que a solicitação seja concluída.*

Observação: o envio de mensagens só funcionará se você adicionar o recurso `SEND_MESSAGE` ao seu provedor de token, conforme descrito acima em [Reconhecer mensagens enviadas pelo usuário atual](#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 a solicitação criando uma nova instância `SendMessageRequest`, passando o conteúdo da mensagem para o construtor. Depois de definir os estados `isSending` e `messageToSend`, chame o método `sendMessage`, que envia a solicitação para a sala de chat. Por fim, limpe o sinalizador `isSending` ao receber a confirmação ou rejeição da solicitação.

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

// ...
```

Experimente o Chatterbox: tente enviar uma mensagem redigindo uma com a sua `MessageBar` e tocando no seu `SendButton`. Você deve ver sua mensagem enviada renderizada dentro da `MessageList` que você criou anteriormente.

### Excluir mensagem
<a name="chat-react-room-actions-deleting-message"></a>

Para excluir uma mensagem de uma sala de chat, você precisa ter a capacidade adequada. As capacidades são concedidas durante a inicialização do token de chat que você usa ao se autenticar em uma sala de chat. Para os propósitos desta seção, a `ServerApp` de [Configure um servidor local de autenticação/autorização](chat-sdk-react-tutorial-chat-rooms.md#chat-react-rooms-auth-server) (na parte 1 deste tutorial) permite que você especifique as capacidades de moderador. Isso é feito em sua aplicação usando o objeto `tokenProvider` que você criou em [Crie um provedor de tokens](chat-sdk-react-tutorial-chat-rooms.md#chat-react-rooms-token-provider) (também na parte 1).

Aqui você modifica sua `Message` adicionando uma função para excluir a mensagem.

Primeiro, abra `App.tsx` e adicione a capacidade `DELETE_MESSAGE`. (`capabilities` é o segundo parâmetro da sua função `tokenProvider`.)

Observação: é assim que sua `ServerApp` informa às APIs do IVS Chat que o usuário associado ao token de chat resultante pode excluir mensagens em uma sala de chat. Em uma situação real, você provavelmente terá uma lógica de backend mais complexa para gerenciar os recursos do usuário na infraestrutura da sua aplicação de servidor.

**TypeScript/JavaScript**:

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

// ...

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

// ...
```

Nas próximas etapas, você atualizará sua `Message` para exibir um botão de exclusão.

Defina uma nova função chamada `onDelete` que aceite uma string como um de seus parâmetros e retorne `Promise`. Para o parâmetro de string, passe o ID da mensagem do 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',
  },
});
```

------

Em seguida, atualize sua `renderItem` para refletir as alterações mais recentes em seu componente `FlatList`.

Em `App`, defina uma função chamada `handleDeleteMessage` e passe-a para a propriedade `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 uma solicitação criando uma nova instância de `DeleteMessageRequest`, passando o ID da mensagem relevante para o parâmetro do construtor e chame `deleteMessage`, que aceita a solicitação preparada acima:

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

// ...
```

------

Em seguida, atualize o estado de `messages` para refletir uma nova lista de mensagens que omita a mensagem que você acabou de excluir.

No hook `useEffect`, receba o evento `messageDelete` e atualize sua matriz de estados de `messages` excluindo a mensagem com um ID correspondente ao parâmetro `message`.

Observação: o evento `messageDelete` pode ser gerado para que as mensagens sejam excluídas pelo usuário atual ou por qualquer outro usuário na sala. Manipulá-lo no manipulador de eventos (em vez de junto à solicitação `deleteMessage`) permite unificar o tratamento da exclusão de mensagens.

**TypeScript/JavaScript**:

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

// ...

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

return () => {
  // ...

  unsubscribeOnMessageDeleted();
};

// ...
```

Agora é possível excluir usuários de uma sala de chat na sua aplicação de chat.

## Próximas etapas
<a name="chat-react-messages-events-next-steps"></a>

A título de experimento, tente implementar outras ações em uma sala, como desconectar um outro usuário.