Usando o Firestore para criar um Chat com React Native

Usando o Firestore para criar um Chat com React Native
Andre Louis Souza Ribeiro
Andre Louis Souza Ribeiro

Compartilhe

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:

Tela de chat de um celular, na parte superior iremos ter  um botão de voltar junto com o texto “Login”, e no meio da tela está escrito “Chat”. Depois disso,no meio da tela existe a tela do chat, onde tem uma conversa que começa com “Olá, como vai? “ do lado esquerdo , abaixo  e no lado direito existe a resposta que é “Muito bem” e  “Estou testando o novo chat que fiz na Alura e está muito show”. Logo abaixo, na parte inferior, terá o teclado do dispositivo.

Então, vamos lá?

Banner da Escola de Mobile: Matricula-se na escola de Mobile. Junte-se a uma comunidade de mais de 500 mil estudantes. Na Alura você tem acesso a todos os cursos em uma única assinatura; tem novos lançamentos a cada semana; desafios práticos. Clique e saiba mais!

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”.
Imagem colorida com fundo azul claro e, no meio da tela, existe um parágrafo, no qual, em uma fonte maior, está escrito “Olá, este é o firebase”. Em fonte menor, está escrito "Ferramenta do google para criar uma infraestrutura de apps, melhorar a qualidade deles e desenvolver a sua empresa”, e logo abaixo existem dois botões, em que neles está escrito “Criar um projeto” e “Ver Documentação.”
  • Você será redirecionado para a tela de criação do projeto, onde deve informar o nome do projeto.
Imagem colorida de uma tela com uma parte na cor branca e outra na cor azul. Na parte branca, existe um texto escrito em fonte grande “Vamos começar nomeando o projeto”, logo abaixo, está escrito em fonte pequena “Nome do projeto” e, logo depois, em uma fonte maior e na cor azul, “chat–firebase”, por último, há um botão azul escrito na cor branca “Continuar.”

Após preencher o nome:

  • Clique em continuar e deixe a opção analytics do projeto desativada; e
  • Clique em “Criar projeto”.
Imagem colorida de uma tela em grande parte na cor branca e menos da metade da tela na cor azul. Na parte branca, há um texto escrito em fonte grande “Google Analytics para seu projeto do Firebase”, logo abaixo, está escrito em tamanho menor uma descrição das funções que o analytics vai implementar no sistema e se desejamos adicionar o mesmo no projeto, e depois disso consta um botão azul escrito na cor branca “Criar projeto” e um outro botão, escrito em azul, que diz  “Anterior”.

Aguarde o carregamento da página até que apareça a mensagem: “Seu novo projeto está pronto”. E então, clique em “Continuar”.

Imagem colorida de uma tela com uma parte na cor branca e outra na cor azul, na parte branca há um ícone formado por um círculo branco e círculos menores dentro, depois está escrito o nome “chat firebase”, logo abaixo, teremos escrito na cor verde “Seu novo projeto está pronto” e um botão na cor azul escrito na cor branca “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”.

Imagem colorida de uma tela com cor de fundo azul claro e no meio da tela está escrito diversos elementos na cor branca, começando por um texto escrito “chat–firebase” do lado teremos escrito “Plano Spark”, abaixo está escrito com uma fonte maior “Comece adicionando o Firebase ao seu aplicativo’ e abaixo desse texto existe cinco ícones, sendo ícones referentes ao iOS, android, Web, unity e flutter, abaixo dos ícones teremos escrito “Adicione um app para começar”

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”.
Imagem colorida de uma tela com uma parte na cor branca e outra na cor azul. Na parte branca, há um texto em fonte grande que diz  “Adicionar o Firebase ao seu app da Web”, logo abaixo, está escrito, em tamanho menor, “1 Registrar App” e, em seguida, um campo de input no qual possui escrito “app-react_native”, logo abaixo do campo input, existe uma caixa para ser selecionada e nessa caixa está escrito “Configure também o Firebase Hosting para este app, Saiba mais”, e um botão azul escrito “Registrar App”, logo abaixo do botão teremos escrito “2 Adicione o SDK do Firebase”.

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:

Imagem colorida em que há uma caixa branca, com diversos conteúdos dentro: o primeiro elemento é um texto em que se lê “2 adicionar o SDK do Firebase”. Abaixo desse texto, há duas opções para serem selecionadas, sendo elas “Usar o npm” e “Usar a tag `<script>`”; abaixo dessas duas opções, está escrita a frase “Se você já estiver usando o npm e um bundler de módulos, como webpack ou Rollup, execute o seguinte comando para instalar o SDK mais recente”, embaixo dessa frase, existe uma caixa cinza com a frase “npm install firebase”. Logo abaixo desta caixa cinza, está escrito “Depois inicialize o firebase e comece a usar os SDKs dos produtos”, e, depois dessa frase existe outra caixa cinza contendo as credenciais do firebase, e após tudo isso, existe um outro botão azul escrito “Continuar no console”.

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”.
Imagem colorida que mostra uma tela com uma parte em azul e outra em branco. Na parte azul, está escrito “Escolha um produto para adicionar ao app”, logo abaixo, pode-se ler “Armazene e sincronize dados de app em milissegundos”. Depois, existem dois quadrados, um ao lado do outro, um tem uma imagem roxa e na parte inferior está escrito “Authentication - Autenticar e gerenciar usuários”, no outro quadrado existe uma imagem laranja e na parte inferior está escrito “Cloud Firestore - Atualizações em tempo real, consultas eficientes e escalonamento automático”.

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.

Imagem  colorida da tela de configuração e criação do banco de dados. A tela está dividida em duas partes, uma parte superior em azul, na qual está escrito “ Criar banco de dados”.  Logo abaixo, está escrito “ 1 Regras seguras para o cloud Firestore” e “2 Defina o local do cloud Firestore”. Na parte branca da tela, há as opções de “modo de produção” e “modo de teste”. E trechos de código referentes a cada um desses modos. E no final, existem dois botões “Cancelar” e “Avançar”.

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.

Imagem colorida que mostra a tela branca do banco de dados do firebase. Na parte superior, está escrito em fonte pequena “chat–firebase” e, logo abaixo, há o título “Cloud Firestore”. Depois disso, há um menu horizontal com as seguintes opções: “Dados, Regras, Índices, Uso e Extensões''. Depois, existe um quadrado branco que contém os dados que estão dentro daquele banco de dados”.

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 e useState 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 e orderBy 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 estado messages e um manipulador de eventos chamado onSend, 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ção mensagemEnviada, 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 valor name 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 pelo useCallback 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ção mensagemEnviada será chamada assim que o usuário enviar uma nova mensagem usando o componente GiftedChat.
  • A função mensagemEnviada ainda irá atualizar o estado messages, adicionando a nova mensagem ao array de mensagens usando a função ‘GiftedChat.append’. Em seguida, a função pega a primeira mensagem do array messages 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ção getMessages passada para o useEffect é 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 estado messages usando o setMessages. Essa função vai usar a função query do Firebase para obter todas as mensagens da coleção chats do banco de dados, ordenando-as pelo valor do createdAt.

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!

Andre Louis Souza Ribeiro
Andre Louis Souza Ribeiro

André é estudante de Engenharia da Computação na UFES. Atualmente, faz parte do Scuba team Mobile | Escola Semente, você o encontrará atuando nos fóruns de mobile. Ele está sempre buscando aprender alguma tecnologia nova ou algo novo na área. Atualmente a linguagem que mais utiliza é o Javascript.

Veja outros artigos sobre Mobile