Artículo original: How to Build a Real-time Chat App with ReactJS and Firebase

En este artículo, voy a mostrarte como crear una app de chat en tiempo real usando React.js y Firebase.

En la app, vamos a permitir que los usuarios se logueen con su cuenta de Google usando el servicio de inicio de sesion de Firebase. También guardaremos y recuperaremos todos los mensajes usando el servicio Firestone de Firebase.

Prerrequisitos

Para este tutorial, deberás tener instalado Node.js en tu sistema, además deberás tener conocimientos intermedios de CSS, JavaScript y ReactJS y conocimientos sobre el uso de la terminal de líneas de comandos. No debes saber utilizar Firebase para hacer el mismo.

¿Que es Firebase?

Firebase es un BaaS (Backend as a Service), una plataforma de backend propiedad de Google que permite a desarrolladores construir aplicaciones para iOS, Android o aplicaciones web.

Nos provee con herramientas para el seguimiento de análisis, reportar y solucionar fallas de aplicaciones y crear pruebas de marketing y productos. Esto, ayuda a los desarrolladores a crear aplicaciones de calidad, hacer crecer su base de usuarios y obtener ganancias.

Para este tutorial, vamos a utilizar dos herramientas: Firebase Authentication y Cloud Firestone.

Firebase Authentication

Firebase Authentication (SDK) es una herramienta de Firebase que permite realizar autenticación de usuarios mediante varios métodos, como contraseñas, números de telefono, cuentas de Google, Facebook, Twitter, GitHub y mas. En este proyecto usaremos la autenticación a través de cuentas de Google.

Cloud Firestore

Cloud Firestones es un servicio de bases de datos no relacionales que nos permite guardar y sincronizar información. Este servicio guarda la información en documentos como pares de clave-valor, y estos documentos en colecciones.

Los documentos, a su vez pueden tener sub-colecciones, permitiéndonos anidar colecciones dentro de otras colecciones, además la información se sincroniza automáticamente entre todos los dispositivos que estén consultando esos datos.

Ahora que ya tienes una idea general de como trabajan Firebase y Cloud Firestone, vamos a trabajar en el proyecto.

Nota: para este proyecto, ya escribí el CSS y preconstruí los componentes para la aplicación de chat, puedes encontrar el código del proyecto final en GitHub y los componentes junto con el CSS en la carpeta "setup", y también puedes ver el proyecto final funcionando en este link

Como crear nuestra aplicación de React

Clona este repositorio de GitHub, borra la carpeta src en el directorio raíz y remplázala con la carpeta "src" que se encuentra en la carpeta "setup".

Alternativamente, puedes crear tu aplicación de React corriendo el comando create-react-app en la terminal.

npx create-react-app react-chat
install-create-react-app
Comando create-react-app corriendo (en la parte superior se ve el comando de instalación: npm install -g create-react.app)

react-chat  es el nombre de la aplicación. Una vez que finaliza correremos el comando  npm install firebase react-firebase-hooks para instalar firebase y react-firebase-hooks.

install-firebase
Comando install firebase react-firebase-hooks corriendo (se aprecia que primeramente se cambio al directorio react-chat

Una vez que finaliza, borra la carpeta src y reemplazala con la que descargaste de la carpeta setup para usar el archivo CSS y los componentes preconstruidos. (Opcionalmente, puedes escribir tus propios componentes y tu propio archivo CSS)

Ahora, tu carpeta src contiene los siguientes componentes:

  • Una carpeta de componentes con un componente NavBar que contiene los botones de Google sign-in y Sign Out,
  • Un componente que le da la Bienvenida al usuario que no está logueado,
  • Un componente Chatbox que solo es visible cuando el usuario está logueado.
  • El componente Message para mostrar los mensajes de los usuarios,y
  • El componente SendMessage que usaremos para que el usuario pueda escribir y enviar sus mensajes.
https://paper-attachments.dropboxusercontent.com/s_B6DDEC735898D3445BBF655B53FFE42B53361DCD6229DE6836CD5302F930DF9D_1667917866994_image2.png

Además, tenemos lo siguiente:

  • Una carpeta img donde se guarda la imagen de Google sign-in y sign-out,
  • un archivo CSS llamado App.css con el código CSS para la aplicación,
  • un archivo llamado App.js con todos los componentes importados dentro,
  • y un archivo llamado index.js.

Corre el comando npm start para ver la aplicación en el navegador, deberías ver algo como esto:

https://paper-attachments.dropboxusercontent.com/s_B6DDEC735898D3445BBF655B53FFE42B53361DCD6229DE6836CD5302F930DF9D_1667916861885_image1.png
Nuestra app de React corriendo en Local

Ahora, creemos una cuenta de Firebase y configuremos nuestro proyecto.

Como configurar el proyecto en Firebase

Si todavía no tienes una cuenta de Firebase, puedes abrir una usando tu correo de Gmail (solo se puede usar el mail de Google).

En la página de inicio, haga clic en comenzar y luego en crear un proyecto.

firebase-web
firebase-web-crear

Completa el formulario para crear el proyecto agregando un nombre de proyecto (en nuestro caso usaremos el nombre React-chat). Si quieres dejar habilitado Google Analytics para tu proyecto déjalo, sino deshabilítalo. Después, haz clic en crear proyecto

https://paper-attachments.dropboxusercontent.com/s_B6DDEC735898D3445BBF655B53FFE42B53361DCD6229DE6836CD5302F930DF9D_1667930368482_image5.png
Creando el proyecto paso 1

Una vez creado, presiona el botón Continuar.

https://paper-attachments.dropboxusercontent.com/s_B6DDEC735898D3445BBF655B53FFE42B53361DCD6229DE6836CD5302F930DF9D_1667930783189_image8.png
Lo que verás mientras Firebase crea tu proyecto.

Elige el tipo de aplicación al que quieres agregar Firebase, para este artículo elegiremos el icono de código porque estamos desarrollando una aplicación web.

firebase-final-1
Elige el tipo de aplicación al que quieres integrar Firebase

Ingresa un sobrenombre para la aplicación y haz clic en el botón registrar app.

https://paper-attachments.dropboxusercontent.com/s_B6DDEC735898D3445BBF655B53FFE42B53361DCD6229DE6836CD5302F930DF9D_1667934485512_image10.png
Registra tu app

En el menú selecciona npm, copia el código (lo vamos a utilizar más tarde) y haz clic en ir a la consola.

https://paper-attachments.dropboxusercontent.com/s_B6DDEC735898D3445BBF655B53FFE42B53361DCD6229DE6836CD5302F930DF9D_1667934988668_image11.png
Código para el SDK de Firebase

Cómo configurar Firebase Authentication

Para configurar Firebase Authentication, ve al menú de la izquierda y presiona sobre Compilación y selecciona Authentication del desplegable.

https://paper-attachments.dropboxusercontent.com/s_B6DDEC735898D3445BBF655B53FFE42B53361DCD6229DE6836CD5302F930DF9D_1667937032772_image12.png
Selecciona Authentication del menú desplegable.

Haz clic en comenzar y selecciona a Google en el menú proveedores de acceso.

https://paper-attachments.dropboxusercontent.com/s_B6DDEC735898D3445BBF655B53FFE42B53361DCD6229DE6836CD5302F930DF9D_1667937105063_image13.png
Elige el método de autenticación.

Presiona sobre el botón de la derecha para habilitar el proyecto y selecciona un correo de soporte, luego haz clic en guardar.

https://paper-attachments.dropboxusercontent.com/s_B6DDEC735898D3445BBF655B53FFE42B53361DCD6229DE6836CD5302F930DF9D_1667937310260_image14.png

Cómo configurar Cloud Firestone

Nuevamente. ve al menú de la izquierda, clickea en compilación y selecciona Firestone. Luego haz clic en crear base de datos y completa el formulario.

image9-2
Configurando Cloud Firestore

En el primer paso, selecciona la localización de la base de datos, por defecto el sistema asignará la ubicación más cercana a la que te encuentras, luego presiona siguiente.

firestone-db-seteo1
Setea la localización de la base de datos y presiona siguiente.

Selecciona el modo de la base de datos, puedes elegir producción o modo de prueba.

El modo de prueba permite que cualquier cliente puede leer o escribir en la base de datos por 30 días. El modo producción significa que nadie puede leer o escribir en la base de datos, por lo que debes escribir tus reglas para brindar acceso a la base de datos.

image10-2
Elige el modo de producción o el modo de pruebas (nosotros elegiremos el modo de producción).

Selecciona modo de producción y presiona el botón crear.

El siguiente paso será editar nuestras reglas, haz clic en la pestaña reglas.

image12-2
Edita las reglas ingresando en la pestaña Reglas.
image13-2
Reemplaza esta regla.

Reemplaza la regla que esta en la pestaña por la siguiente y presiona el boton publicar.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read: if true;
      allow create, update, delete, write: if request.auth != null;
    }
  }
}

Analicemos el código, la primer parte,  allow read: if true; significa que cualquiera puede leer tu base de datos, mientras que el bloque de código siguiente allow create, update, delete, write: if request.auth != null; significa que solo los clientes autenticados pueden crear, actualizar, borrar y escribir datos en la base de datos.

Puedes comenzar agregando o creando una colección en tu base de datos o crear una automáticamente en la aplicación que estamos desarrollando, lo que haremos después. Si quieres crear una colección en Cloud Firestone, vuelve a la pestaña de datos presionando en la misma y presiona el botón iniciar coleccion.

Ingresa el nombre de la colección, por ejemplo "messages" y clickea en siguiente.

image14-2
Iniciando una colección en Firestone.

Ahora, crea el documento para la colección,

image15-1
Creando un documento para la colección.

Clickea en ID automático, de esa forma el sistema generará el ID de forma automática, o si lo prefieres ingresa uno tu.

Luego, se crea el par clave->valor para el documento. El campo llamado "Campo" representa el nombre de la clave, el campo "Tipo" nos dice que valor almacena (cadena de texto, number, timeStamp, etc), y finalmente el campo "Valor" es lo que guardamos en esta clave.

Puedes seguir agregando más documentos presionando en el enlace "Agregar campo", sino presiona en Guardar para que se guarde la colección.

Nuestro proyecto de Firebase ya esta correctamente seteado, volvamos a la aplicación de React.

Cómo configurar Firebase en React

En la carpeta src, crea un archivo llamado firebase.js y pega el código que copiamos al configurar firebase.

Tambien importemos los servicios getAuth  y getFirestore desde Autenticación para Web y Firestore en la nube para web respectivamente. Puedes leer más sobre las bibliotecas disponibles para Firebase en la página de la documentación.

Nuestro archivo firebase.js debe verse asi:

// Import the functions you need from the SDKs you need
import { initializeApp } from "firebase/app";
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries
import { getAuth } from "firebase/auth";
import { getFirestore } from "firebase/firestore";

// Your web app's Firebase configuration
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {
  apiKey: LA_CLAVE_PARA_LA_APLICACION_VA_AQUI(CLAVE_API),
  authDomain: EL_DOMINIO_DE_AUTENTICACION_PARA_LA_APP_VA_AQUI,
  projectId: EL_ID_DEL_PROYECTO_PARA_LA_APP_VA_AQUI,
  storageBucket: EL_BUCKET_PARA_LA_APLICACION_VA_AQUI,
  messagingSenderId: EL_ID_PARA_ENVIAR_LOS_MENSAJES_VA_AQUI,
  appId: EL_APP_ID_DE_LA_APLICACION_DE_REACT_VA_AQUI,
};

Cómo implementar Firebase dentro de nuestra aplicación React

Cómo autenticar usuarios con su cuenta de Google

Nosotros queremos que los usuarios tengan acceso a la aplicación de chat y que en caso de que estén autenticados puedan enviar mensajes, si no lo están queremos que vean la página de bienvenida para poder loguearse usando el botón de Google sign-in, y si esta logueado debe poder ver el botón de Sign-out para salir del chat.

Esta autenticación será controlada por el componente NavBar, que contiene ambos botones (sign-in y sign-out).

En nuestro componente NavBar, importaremos nuestra imagen de Google "sign-in", y la guardaremos como la constante llamada GoogleSignin. También tendremos un estado llamado user, seteado como falso, una función llamada googleSignIn que setea el estado de user como verdadero, y una función llamada signOut que setea el estado de user como falso.

También tenemos un elemento nav con un tag h1 que representa el título de nuestra app y dos botones que se renderizan condicionalmente en base al estado del componente user

import React, { useState } from "react";
import GoogleSignin from "../img/btn_google_signin_dark_pressed_web.png";

const NavBar = () => {
  const [user, setUser] = useState(false);
  const googleSignIn = () => {
    setUser(true);
  };
  const signOut = () => {
    setUser(false);
  };
  return (
    <nav className="nav-bar">
      <h1>React Chat</h1>
      {user ? (
        <button onClick={signOut} className="sign-out" type="button">
          Sign Out
        </button>
      ) : (
        <button className="sign-in">
          <img
            onClick={googleSignIn}
            src={GoogleSignin}
            alt="sign in with google"
            type="button"
          />
        </button>
      )}
    </nav>
  );
};
export default NavBar;

Hagamos un cambio en el componente NavBar, importando lo siguiente:

import { auth } from "../firebase";
import { useAuthState } from "react-firebase-hooks/auth";
import { GoogleAuthProvider, signInWithRedirect } from "firebase/auth";

Reemplaza el estado del usuario con el siguiente código:

const [user] = useAuthState(auth);

Y edita las funciones googleSignIn y signOut:

const googleSignIn = () => {
  const provider = new GoogleAuthProvider();
  signInWithRedirect(auth, provider);
};
const signOut = () => {
  auth.signOut();
};

La función useAuthState se dispara en el momento que el usuario se loguea o desloguea, permitiéndonos acceder a los detalles del usuario. Actualmente, el estado del usuario es null, una vez que te logueas, el estado del usuario cambiará a la información suministrada por el método de autenticación (en este caso, Google).

En la función googleSignIn, le indicamos a Firebase que el el usuario quiere autenticarse con Google usando el GoogleAuthProvider(). También lo redirige a la página de inicio de sesión de Google.

Luego de el correcto inicio de sesión del usuario, sus datos son almacenados en auth, y el usuario es redireccionado a la app. La función signOut borra la información almacenada de autenticación, retornando ésta a null. El nuevo estado almacenado también determina qué botón debe renderizarse.

Agreguemos también autenticación a nuestro archivo App.js. Importa lo siguiente:

import { auth } from "./firebase";
import { useAuthState } from "react-firebase-hooks/auth";

Agrega el nuevo user state, para que podamos renderizar el componente Welcome si el usuario no está logueado o el componente Chatbox si el usuario ya se autenticó.

const [user] = useAuthState(auth);

El codigo final debe lucir así:

import { auth } from "./firebase";
import { useAuthState } from "react-firebase-hooks/auth";
import "./App.css";
import NavBar from "./components/NavBar";
import ChatBox from "./components/ChatBox";
import Welcome from "./components/Welcome";

function App() {
  const [user] = useAuthState(auth);
  return (
    <div className="App">
      <NavBar />
      {!user ? <Welcome /> : <ChatBox />}
    </div>
  );
}
export default App;

Al probar nuestras nuevas funciones de sign-in y sign-out, veremos lo siguiente:

ezgif-4-b6465d1647-1
App demo

Ahora, hagamos lo mismo con el componente Welcome, que ahora tiene el siguiente código:

import React from "react";
import GoogleSignin from "../img/btn_google_signin_dark_pressed_web.png";

const Welcome = () => {
  const googleSignIn = () => {};

  return (
    <main className="welcome">
      <h2>Welcome to React Chat.</h2>
      <img src="/logo512.png" alt="ReactJs logo" width={50} height={50} />
      <p>Sign in with Google to chat with with your fellow React Developers.</p>
      <button className="sign-in">
        <img
          onClick={googleSignIn}
          src={GoogleSignin}
          alt="sign in with google"
          type="button"
        />
      </button>
    </main>
  );
};
export default Welcome;

Importaremos lo siguiente:

import { auth } from "../firebase";
import { GoogleAuthProvider, signInWithRedirect } from "firebase/auth";

y tambien editaremos la funcion googleSignIn:

const googleSignIn = () => {
    const provider = new GoogleAuthProvider();
    signInWithRedirect(auth, provider);
};

Ahora, podremos loguearnos desde el botón que se renderiza en el componente Welcome:

video2-1
Updated app demo

Como enviar y almacenar mensajes en Firebase:

Actualmente, estamos mostrando un mensaje de prueba de nuestro componente Message y, el botón Send no realiza ninguna acción. Cuando ingresamos un mensaje y pulsamos el botón Send, queremos que el mensaje se envíe de inmediato a la aplicación.

Así, que editemos el componente SendMessage:

Primero, importamos useState de React, auth y db  de nuestro archivo de configuración de firebase, y addDoc, collection y serverTimestamp de la librería Firestore.

import React, { useState } from "react";
import { auth, db } from "../firebase";
import { addDoc, collection, serverTimestamp } from "firebase/firestore";

Crearemos un estado llamado message que inicialmente esté definido como una cadena vacía y se pase como valor a la etiqueta input. La funcion onChange es también agregada a el input, que setea el estado del message en lo que el usuario tipee.

const SendMessage = () => {
  const [message, setMessage] = useState("");
    
  return (
    <form className="send-message">
      <input
        ...
        value={message}
        onChange={(e) => setMessage(e.target.value)}
      />
      <button type="submit">Send</button>
    </form>
  );
};

También creamos una función llamada sendMessage, y agregamos el atributo onSubmit en nuestro formulario, que ejecuta la función sendMessage cuando el usuario clickea en el botón Send (enviar). Nótese que el botón debe tener el tipo type="submit"  para que la función funcione.

 const sendMessage = async (event) => {
    event.preventDefault();
    if (message.trim() === "") {
      alert("Enter valid message");
      return;
    }
    const { uid, displayName, photoURL } = auth.currentUser;
    await addDoc(collection(db, "messages"), {
      text: message,
      name: displayName,
      avatar: photoURL,
      createdAt: serverTimestamp(),
      uid,
    });
    setMessage("");
  };
  
  return (
    <form onSubmit={(event) => sendMessage(event)} className="send-message">
...

La función sendMessage es una funcion asincrona. Primero chequea si el el usuario esta intentando enviar una cadena vacía o espacios vacíos como un mensaje y, en caso de que así sea alerta al usuario.

Si el mensaje no es una cadena vacía, toma del usuario los siguientes datos dela información proporcionada por auth al logguearse: uid, displayName y photoURL. Estos datos corresponden con el identificador único del usuario, su nombre y la URL de la foto del usuario, respectivamente.

Luego, usa la función addDoc() para crear un documento dentro de la colección messages de nuestra base de datos, a la que accede gracias al archivo que importamos. En caso de que la colección no exista, crea una por nosotros.

También crea un par de llave-valor, guardando nuestro mensaje en text, displayName en name, guardando el momento en el que el mensaje fue guardado en nuestra base de datos en la columna createAt, y el uid.

Estos pares de llave-valor, conforman los datos de nuestro documento. Una vez que se completa la acción, se restablece el estado del mensajea una cadena vacía.

Como recuperar mensajes de nuestra base de datos

Luego de enviar el mensaje del usuario, debemos mostrarlo en la pantalla. Vayamos a nuestro componente chatBox e importemos lo siguiente:

import { useEffect, useRef, useState } from "react";
import {
  query,
  collection,
  orderBy,
  onSnapshot,
  limit,
} from "firebase/firestore";
import { db } from "../firebase";

Creamos el hook useEffect que correra cada vez que se realizan cambios en el thatroom, por ejemplo enviar o borrar un mensaje.

useEffect(() => {
  const q = query(
    collection(db, "messages"),
    orderBy("createdAt", "desc"),
    limit(50)
  );
  const unsubscribe = onSnapshot(q, (QuerySnapshot) => {
    const fetchedMessages = [];
    QuerySnapshot.forEach((doc) => {
      fetchedMessages.push({ ...doc.data(), id: doc.id });
    });
    const sortedMessages = fetchedMessages.sort(
      (a, b) => a.createdAt - b.createdAt
    );
    setMessages(sortedMessages);
  });
  return () => unsubscribe;
}, []);

En el hook useEffect, tenemos la constante q, una consulta de Firebase que busca los mensajes dentro de la base de la colección messages de nuestra base de datos, luego ordena los documentos obtenidos basados en la llave createAt y devuelve un máximo de 50 documentos (mensajes guardados)

La constante unsubscribe representa la función onSnapshot, que escucha los cambios en el documento, esta función tiene un arreglo vacío llamado messages.

El bucle forEach itera entre todos los documentos de la colección y guarda la información en un nuevo arreglo. Luego, asigna el arreglo inicial de mensajes al nuevo arreglo de mensajes.

También usamos el método map en nuestro arreglo de mensajes para  cada mensaje/documento en nuestro componente message.

{messages?.map((message) => (
  <Message key={message.id} message={message} />
))}

El codigo completo luce asi:

import React, { useEffect, useRef, useState } from "react";
import {
  query,
  collection,
  orderBy,
  onSnapshot,
  limit,
} from "firebase/firestore";
import { db } from "../firebase";
import Message from "./Message";
import SendMessage from "./SendMessage";

const ChatBox = () => {
  const [messages, setMessages] = useState([]);
  const scroll = useRef();

  useEffect(() => {
    const q = query(
      collection(db, "messages"),
      orderBy("createdAt", "desc"),
      limit(50)
    );

    const unsubscribe = onSnapshot(q, (QuerySnapshot) => {
      const fetchedMessages = [];
      QuerySnapshot.forEach((doc) => {
        fetchedMessages.push({ ...doc.data(), id: doc.id });
      });
      const sortedMessages = fetchedMessages.sort(
        (a, b) => a.createdAt - b.createdAt
      );
      setMessages(sortedMessages);
    });
    return () => unsubscribe;
  }, []);

  return (
    <main className="chat-box">
      <div className="messages-wrapper">
        {messages?.map((message) => (
          <Message key={message.id} message={message} />
        ))}
      </div>
      {/* when a new message enters the chat, the screen scrolls down to the scroll div */}
      <span ref={scroll}></span>
      <SendMessage scroll={scroll} />
    </main>
  );
};

export default ChatBox;

Vayamos a nuestro componente message, y rendericemos los datos recibidos en el navegador.

import React from "react";
import { auth } from "../firebase";
import { useAuthState } from "react-firebase-hooks/auth";
const Message = ({ message }) => {
  const [user] = useAuthState(auth);

  return (
    <div
      className={`chat-bubble ${message.uid === user.uid ? "right" : ""}`}>
      <img
        className="chat-bubble__left"
        src={message.avatar}
        alt="user avatar"
      />
      <div className="chat-bubble__right">
        <p className="user-name">{message.name}</p>
        <p className="user-message">{message.text}</p>
      </div>
    </div>
  );
};
export default Message;

Importamos auth y useAuthState, y almacenamos los datos del usuario en  user. Deconstruimos el prop message y asignamos el avatar al atributo src del componente img. También reemplazamos el nombre y el mensaje "de prueba" con el mensaje obtenido desde message.

También aplicamos una condición al estilo CSS según el uid del autor del mensaje, entonces si el uid del autor del mensaje es el mismo que el del usuario logueado, se aplica al div el estilo definido en el selector derecho; en caso contrario no se agrega ningún estilo adicional.

Actualmente, todos  los mensajes se posicionan a la izquierda, así que si el autor del mensaje es el usuario logueado, sus mensajes se posicionaran a la derecha. Veamos esa dinámica en acción en el navegador:

video3-1
Demostración de la app actualizada

El mensaje es enviado y almacenado en nuestra base de datos, luego todos los mensajes se recuperan y la sala es actualizada en tiempo real con los mensajes nuevos.

El nombre y el avatar de cada usuario son  mostrados en cada tarjeta, pero también podemos ver que el chat no se desliza automáticamente hacia abajo cuando llega un nuevo mensaje. Vamos a arreglar eso.

Como hacer que el chat se desplace hasta el final

Vayamos al archivo ChatBox.js, importemos el hook useRef y creemos una constante llamada scroll:

import React, { useEffect, useRef, useState } from "react";
...
const scroll = useRef();

Crearemos un elemento span con un atributo ref conectado al valor de scroll,y , también pasamos el  scroll en nuestro componente message.

Luego, creamos un elemento span con un atributo ref cuyo valor es scroll, y también pasamos scroll a nuestro componente SendMessage:

<main className="chat-box">
   ...
   {/* when a new message enters the chat, the screen scrolls dowwn to the scroll div */}
   <span ref={scroll}></span>
   <SendMessage scroll={scroll} />
</main>

Luego vamos al componente Messages, accedemos a la constante scroll, y agregamos scroll.current.scrollIntoView({ behavior: "smooth" }) al final de nuestra función sendMessage.

Este código le indica al navegador que el scroll span debe ser visible después de enviar un mensaje. Por eso ponemos la etiqueta span al final de cada mensaje.

const SendMessage = ({ scroll }) => {

  const sendMessage = async (event) => {
   ...
    setMessage("");
    scroll.current.scrollIntoView({ behavior: "smooth" });
  };
  ...
};

Volviendo al navegador, deberíamos ver que el chat se desplaza automáticamente hasta el final cuando del usuario envía un mensaje.

video4-1
Demo mostrando como el chat se desliza hasta el final con un nuevo mensaje.

Como agregar dominios autorizados

Cuando desplegamos nuestra aplicacion en React, es indispensable agregar nuestro dominio a la lista de dominios autorizados en Firebase. Este paso, asegura que nuestra app se comunique correctamente con los servicios de Firebase, veamos como hacerlo:

En la consola de Firebase, navega hasta la sección Autenticación y haz click en la pestaña de configuración. Deslízate hasta la parte de Dominios autorizados; a continuación clickea en el botón agregar un dominio. Luego agrega el o los dominios donde la aplicación será desplegada.

Por ejemplo, si desplegaras la aplicación en la dirección https://my-react-chat-app.com, ingresa my-react-chat-app.com como un dominio autorizado, y clickea el boton agregar para guardar los cambios.

firestone-agregar-dominio-1

Agregando el dominio donde desplegaras tu app a la lista de dominios autorizados, le brindas permisos a los servicios de Firestone para ser accedidos desde ese dominio. Si no hiciéramos esto, encontraríamos errores al intentar establecer conexión o realizar operaciones con Firebase.

Para terminar

Y, así es como llegamos al final de la construcción de esta aplicación de chat en tiempo real, ¡felicitaciones!.

En este tutorial, aprendimos a usar Firebase y React para crear una aplicacion de  chat en tiempo real. También autenticamos a los usuarios usando el método de logueo por cuenta de Google de Firetone y, guardamos los mensajes del chat usando Cloud Firestore. Finalmente, aprendimos a usar algunos servicios y librerías de Firestone.

Puedes encontrar el código de este proyecto en GitHub y puedes probar la aplicación desplegada usando el siguiente enlace.

Si disfrutaste este articulo, por favor compártelo para ayudar a otros desarrolladores, también puedes visitar mi blog para leer mas artículos o puedes seguirme en  Twitter o LinkedIn.

Hasta la próxima, byeeeeee!

HoDL1vbXj-1-1-