Usando o Firestore para criar um Chat com React Native
Resumo
Neste artigo, vamos aprender como construir um chat em tempo real utilizando o Firestore com React Native. Além disso, vamos aprender também sobre o funcionamento de uma biblioteca de chat completíssima, como criar o seu projeto no Firebase e integrá-lo com a sua aplicação. Abaixo você tem uma prévia do que será feito neste artigo:
Então, vamos lá?
Introdução
O chat é uma funcionalidade importante nas aplicações atuais. Muitas redes sociais, como o Facebook e o Instagram, possuem recursos de chat que permitem que os usuários se comuniquem diretamente com amigos e seguidores, compartilhando ideias e experiências. Também, é uma ferramenta útil para colaboração e resolução de problemas.
Mas será que é muito difícil desenvolver esse recurso? Vamos convencer você de que não é! Nesse artigo, você vai aprender como criar um chat em tempo real, utilizando ferramentas e tecnologias disponíveis no mercado.
Então, vamos entender como construir essa funcionalidade tão conhecida com a ferramenta chamada Firestore?
Neste artigo iremos utilizar o Firestore e caso tenha interesse em saber mais sobre esse tema, indicamos o artigo Entendendo o Firebase e suas principais funcionalidades.
Criando e configurando o Firebase
Para utilizar o Firestore, a primeira coisa que você precisa fazer é acessar o console no site do firebase e seguir os seguintes passos:
- Crie um novo projeto clicando em “Criar um projeto”.
- Você será redirecionado para a tela de criação do projeto, onde deve informar o nome do projeto.
Após preencher o nome:
- Clique em continuar e deixe a opção analytics do projeto desativada; e
- Clique em “Criar projeto”.
Aguarde o carregamento da página até que apareça a mensagem: “Seu novo projeto está pronto”. E então, clique em “Continuar”.
Após essa ação, você será redirecionado para a tela principal do projeto, e vai se deparar com a seguinte mensagem: "Comece adicionando o Firebase ao seu aplicativo”.
Para integrar uma aplicação React Native ao Firebase, você deve realizar os seguintes passos:
- Escolha a opção de adicionar utilizando Web;
- Cadastre a aplicação que irá utilizar esse projeto firebase;
- Insira um nome e clique em “Registrar App”.
Após essa ação, vai aparecer uma tela com todas as credenciais que serão utilizadas para fazer a conexão da aplicação com o projeto Firebase. Na imagem abaixo, você tem um exemplo dessa tela:
Esse é um exemplo das minhas credenciais para conectar no projeto do firebase, mas quando você criar o seu projeto vão ser credenciais diferentes.
Nessa etapa, é importante que você copie todo esse arquivo de configuração que o Firebase fornece e guarde esse arquivo em algum lugar, pois iremos utilizá-lo no código mais a frente.
Configuração do Firestore
Para ativar o serviço do Cloud Firestore no projeto Firebase que foi criado anteriormente, você deve:
- Clique em “Cloud Firestore”, no console do Firebase;
- Clique em “criar um banco de dados”.
Com isso, vai abrir uma aba perguntando se queremos “iniciar no modo de produção” ou no “iniciar no modo de teste”. Selecione a opção “iniciar no modo de teste” para não precisar fazer configurações adicionais no projeto.
Escolha o valor “southamerica-east1(São Paulo)”, que é o local onde o Firestore irá ficar, e depois clique em “ativar”. Você vai ser redirecionado para a tela do filestorage que acabou de ser criada.
Agora, sim, seu banco de dados está criado e pronto para ser utilizado.
Com essas configurações iniciais feitas, já temos a base para criar o chat: um banco de dados! É ele que vai armazenar as mensagens do chat.
Mas, além de um banco de dados para guardar as mensagens, vai ser necessário para criar o chat:
- Implementar o banco de dados na aplicação react native
- Criar toda a estrutura do chat que irá ficar fazendo a troca de mensagens e isso será feito com uso de uma biblioteca.
Assim, vamos em seguida entender a biblioteca de programação que usaremos para criar a estrutura do chat.
Vamos lá?
Relembrando o que é uma biblioteca de programação
As bibliotecas são um conjunto de códigos reutilizáveis que possuem funcionalidades específicas, e que podem ser utilizadas por outros programas sem necessidade de reescrita do código. A ideia é aproveitar códigos de problemas que já foram solucionados por outras pessoas.
Na indústria de software, as bibliotecas de programação são amplamente utilizadas porque permitem que os desenvolvedores de software economizem tempo e esforço ao utilizar um código já testado e comprovado ao invés de escrever tudo do zero.
E claro que, para facilitar nosso processo na construção do Chat, vamos aproveitar códigos que já foram elaborados com a biblioteca GiftedChat.
Instalando a biblioteca “react-native-gifted-chat”
Para criação do chat, oriento que você utilize a biblioteca react-native-gifted-chat
, que já vai trazer consigo o formato e as funcionalidades do chat.
Além disso, essa biblioteca já diferencia mensagens de diferentes pessoas na tela e possui uma funcionalidade bem interessante, pois toda vez que enviarmos uma mensagem, é criado um objeto dessa mensagem contendo os seguintes campos:
- id: Um identificador da mensagem gerado de forma aleatória;
- createdAt: Um marcador de tempo dizendo quando a mensagem foi criada;
- text: O conteúdo de texto da mensagem; e
- user: Informações do usuário que enviou aquela mensagem.
Então, para instalar a biblioteca no seu projeto, execute o seguinte comando:
npm i react-native-gifted-chat
Caso tenha interesse em conhecer mais sobre essa biblioteca, acesse o repositório oficial.
Com a biblioteca instalada, é hora de fazer a programação do chat. Vamos lá!
Criando o nosso Chat
Como o objetivo principal desse artigo é a criação do chat (e para que o artigo não fique tão extenso), sua aplicação em React Native já deve está criada e com a navegação funcionando corretamente.
Caso tenha alguma dúvida na parte de criação da aplicação recomendo o artigo React Native: o que é e tudo sobre o Framework. Além disso, você pode baixar o projeto no repositório do github.
Tudo pronto, podemos continuar!
Para realizar esse processo você precisa:
- Instale o Firebase no projeto;
- Adicione o arquivo “firebase.js”;
- Crie duas telas: uma de autenticação (login) e outra que será a tela do chat.
É válido reforçar que a nossa aplicação será composta por uma única tela de chat. Logo, todos os dispositivos estarão no mesmo ambiente, funcionando como um grupo do WhatsApp, por exemplo.
Instalando o Firebase no projeto
Com o banco de dados criado, precisamos instalar o Firebase no projeto React Native. Para isso, utilize a versão 9.13.0 do Firebase - que é a versão utilizada no desenvolvimento deste projeto.
Recomendo que você use essa versão mesmo que novas versões tenham sido lançadas, para garantir que tudo funcione normalmente.
Utilize o seguinte comando, para realizar a instalação:
npm install [email protected] --save
Prontinho! O Firebase está instalado e você só precisa adicioná-lo ao projeto.
Adicionando Firebase ao projeto
Você precisará de um arquivo de configuração do Firebase na aplicação React Native. Para isso:
- Crie uma pasta chamada
config
; - Crie um arquivo chamado
firebase.js
, dentro de ‘config’.
Nesse arquivo firebase.js
, deverá ser colado o código que foi criado na ‘configuração do Firebase’ anteriormente. Aqui, o código é o seguinte:
import { initializeApp } from "firebase/app";
import { getFirestore } from "firebase/firestore"; //* for Cloud Firestore
// Adicione aqui as suas credenciais do Firebase
const firebaseConfig = {
apiKey: "AIzaSyAGzPAA-cySp5C_xYdkdNZEiJ3NuB8MwzA",
authDomain: "chat--firebase-662ad.firebaseapp.com",
projectId: "chat--firebase-662ad",
storageBucket: "chat--firebase-662ad.appspot.com",
messagingSenderId: "504224726320",
appId: "1:504224726320:web:f554081115ca495bf79cf5"
};
// Initialize Firebase
export const app = initializeApp(firebaseConfig);
export const database = getFirestore(app);
Esse código é o mesmo que foi fornecido anteriormente na parte de “configuração do firebase”. É preciso apenas adicionar a ele a importação do
getFirestore
e a exportação do firebase e do firestore.
Com o firestore configurado, é a hora de criar a tela de autenticação.
Tela de autenticação
O código da tela de autenticação deverá ficar da seguinte forma:
import { View , Text, TextInput, Button} from "react-native";
import { styles } from "./styles";
import { useState } from "react";
export default function Login({ navigation }) {
const [name, setName] = useState('');
return (
<View style={styles.container}>
<View style={styles.boxInput}>
<Text>Nome de Usuário</Text>
<TextInput
style={styles.input}
onChangeText={setName}
/>
</View>
<Button
title="Entrar"
onPress={() => navigation.navigate('Chat', { name: name })}
/>
</View>
)
}
A tela de autenticação deverá ter:
- um campo que irá receber o nome de usuário;
- um botão de logar, que deve navegar para a próxima tela e enviar o nome de usuário como parâmetro para a próxima tela.
Lembre-se: vamos utilizar o nome de usuário para diferenciar os usuários que estão mandando mensagem no chat.
Essa tela é importante para conseguirmos fazer a autenticação e depois diferenciar os usuários que estão utilizando a aplicação.
Com a tela de autenticação pronta, você pode partir para a tela do chat.
Tela do Chat
A tela do Chat é onde tudo vai acontecer: todas as importações, todas as chamadas de funções, consultas e envios para o banco de dados. Em resumo, a tela de chat vai exibir uma lista de mensagens enviadas e vai permitir que o usuário envie novas mensagens, e essas serão todas armazenadas no banco de dados do Firebase.
Para facilitar o entendimento do código da tela do chat, vamos dividir a explicação em partes:
- Importações do arquivo;
- Criação das variáveis;
- Retorno da tela de conteúdo;
- Função de ‘mensagemEnviada’;
- Recuperação de mensagens;
- E a função onSnapShot.
Vamos começar?
A primeira parte será a de importações do arquivo, na qual você deverá ter a seguinte estrutura:
import { useRoute } from "@react-navigation/native";
import { GiftedChat } from 'react-native-gifted-chat'
import { useCallback, useEffect, useState } from "react";
//importação do firebase e database
import { collection, addDoc,onSnapshot, query,orderBy } from "firebase/firestore";
import { database } from "../config/firebase";
O código começa importando alguns ‘módulos’ e componentes do React e do React Native. Vamos entendê-los?
- O módulo
useRoute
é do pacote@react-navigation/native
e é usado para obter informações sobre a rota atual da aplicação; - A biblioteca GiftedChat é a biblioteca, mencionada anteriormente, que irá fornecer a funcionalidade básica de chat, como exibir mensagens e permitir que o usuário envie novas mensagens;
- Os módulos
useCallback
,useEffect
euseState
são hooks do React que fornecem diversas funcionalidades, como permitir que uma função seja executada apenas quando certas condições são atendidas ou armazenar o estado de um componente; - Os módulos
collection
,addDoc
onSnapshot
query
eorderBy
são funções do Firebase que permitem acessar e manipular os dados em um banco de dados do Firebase. O módulo database é um objeto que representa a conexão com o banco de dados do Firebase.
A segunda parte será a de criação das variáveis, onde você conseguirá sincronizar e consultar todas as mensagens utilizando apenas uma variável no código. Para isso, é preciso criar uma variável chamada ‘messages’, que será um ‘Array’ vazio por enquanto.
const [messages, setMessages] = useState([]);
A terceira parte será a de retornar, na tela, o conteúdo do chat, e, por estarmos utilizando a biblioteca ‘GiftedChat’ para representar o chat e suas funcionalidades, você deve retornar o componente GiftedChat
que foi importado com algumas configurações a mais adicionadas. O resultado seria o seguinte:
return (
<GiftedChat
messages={messages}
onSend={msg => mensagemEnviada(msg)}
user={{
_id: name,
}}
/>
)
Vamos entender como funciona cada um deles?
- O componente
GiftedChat
é renderizado com as mensagens armazenadas no estadomessages
e um manipulador de eventos chamadoonSend
, que é chamado assim que o usuário envia uma nova mensagem; - O
onSend
é uma funcionalidade da própria biblioteca ‘GiftedChat’, e toda vez que uma mensagem for enviada no chat, esse manipulador de eventos vai passar as novas mensagens para a funçãomensagemEnviada
, que as adiciona ao banco de dados e atualiza o estado messages; - O componente
GiftedChat
também recebe um objeto user com um identificador único _id que será o valorname
recebido por parâmetro. Essa parte será importante para deixar claro na tela, quem está enviando a mensagem e quem está recebendo.
A quarta parte do código será a função mensagemEnviada
, que deve ficar da seguinte forma:
//função que aciona assim que envia a mensagem no aplicativo
const mensagemEnviada = useCallback((messages = []) => {
setMessages(previousMessages =>{
GiftedChat.append(previousMessages, messages)
}
);
const { _id, createdAt, text, user } = messages[0];
addDoc(collection(database, "chats"), {
_id,
createdAt,
text,
user,
});
}, []);
E para quê serve cada parte?
- A função
mensagemEnviada
é um callback memorizado retornado pelouseCallback
e esse retorna um callback que é memorizado entre as renderizações do componente, ou seja, a função só é recriada se uma de suas dependências mudar. A funçãomensagemEnviada
será chamada assim que o usuário enviar uma nova mensagem usando o componenteGiftedChat
. - A função
mensagemEnviada
ainda irá atualizar o estadomessages
, adicionando a nova mensagem ao array de mensagens usando a função ‘GiftedChat.append’. Em seguida, a função pega a primeira mensagem do arraymessages
e a envia para o banco de dados do Firebase usando a função ‘addDoc’ do Firebase.
A quinta parte do código será uma das mais importantes: a função de recuperar as mensagens antigas e atualizar em tempo real se novas mensagens chegarem. O código deve ficar assim:
useEffect(() => {
async function getMessages() {
const values = query(collection(database, 'chats'), orderBy('createdAt', 'desc'));
onSnapshot(values, (snapshot) => setMessages(
snapshot.docs.map(doc => ({
_id: doc.data()._id,
createdAt: doc.data().createdAt.toDate(),
text: doc.data().text,
user: doc.data().user,
}))
));
}
getMessages();
}, []);
E para que serve cada uma delas?
- O
useEffect
é um gancho do React que é executado assim que o componente é montado e sempre que algumas de suas dependências mudam. No caso, a funçãogetMessages
passada para ouseEffect
é executada assim que o componente é montado. - A função
getMessages
é uma função assíncrona que obtém as mensagens do banco de dados do Firebase e as armazena no estadomessages
usando osetMessages
. Essa função vai usar a funçãoquery
do Firebase para obter todas as mensagens da coleçãochats
do banco de dados, ordenando-as pelo valor docreatedAt
.
Essa ordenação é extremamente importante para conseguirmos mostrar um histórico da conversa no chat, uma funcionalidade que não pode faltar.
Por fim, temos a função que vai de fato trazer o real time (tempo real) para o nosso chat, o onSnapShot
. Essa função do Firebase é usada para criar um listener que fica observando as mensagens e atualiza o estado messages
sempre que houver alterações no banco de dados.
O snapshot é passado para a função de callback, que extrai os dados das mensagens do snapshot e as armazena no estado messages
. Além disso, o onSnapshot
deve ser inicializado apenas uma vez. Depois disso, qualquer alteração no banco de dados será “escutada” e assim o estado messages
será atualizado.
Logo, a versão completa do código da tela do chat deverá ficar da seguinte forma:
import { useRoute } from "@react-navigation/native";
import { GiftedChat } from 'react-native-gifted-chat'
import { useCallback, useEffect, useState } from "react";
//importação do firebase e database
import { collection, addDoc,onSnapshot, query,orderBy } from "firebase/firestore";
import { database } from "../config/firebase";
export default function Chat() {
const [messages, setMessages] = useState([]);
const route = useRoute();
const { name } = route.params;
useEffect(() => {
async function getMessages() {
const values = query(collection(database, 'chats'), orderBy('createdAt', 'desc'));
onSnapshot(values, (snapshot) => setMessages(
snapshot.docs.map(doc => ({
_id: doc.data()._id,
createdAt: doc.data().createdAt.toDate(),
text: doc.data().text,
user: doc.data().user,
}))
));
}
getMessages();
}, []);
//função que aciona assim que envia a mensagem no aplicativo
const mensagemEnviada = useCallback((messages = []) => {
setMessages(previousMessages =>{
GiftedChat.append(previousMessages, messages)
}
);
const { _id, createdAt, text, user } = messages[0];
addDoc(collection(database, "chats"), {
_id,
createdAt,
text,
user,
});
}, []);
return (
<GiftedChat
messages={messages}
onSend={msg => mensagemEnviada(msg)}
user={{
_id: name,
}}
/>
)
}
Caso tenha interesse em baixar e testar a versão completa do projeto, você pode encontrá-lo nesse link do github.
Conclusão
Ao longo deste artigo, aprendemos que o chat online é uma ferramenta muito útil para comunicação e interação em tempo real. Ele permite que as pessoas se comuniquem e troquem informações de maneira rápida e fácil, independentemente de onde estejam, sendo um diferencial na sua aplicação.
Com isso, aprendemos como criar um chat em tempo real em pouco tempo e com poucas linhas de código, utilizando o banco de dados Firestore, um recurso do Firebase que possui diversas funcionalidades como: atualizações em tempo real, suporte off-line, escalabilidade, flexibilidade e muito mais.
Caso tenha interesse em aprofundar o seu conhecimento em Firebase e Firestore, e construir funcionalidades incríveis para a suas aplicações, conheça e faça a formação Firebase com React Native da Alura e mergulhe cada vez mais fundo no mundo da tecnologia.
Eu espero que tenha gostado, bons estudos e até a próxima!