DEV Community

Cover image for Making a Chat App with ReactJS and Firebase
Pranshu Jha
Pranshu Jha

Posted on • Updated on

Making a Chat App with ReactJS and Firebase

We'll be making a simple chat app which works like a youtube superchat, with ReactJS and Firebase in just 5 steps. So, let's jump right into it!

Note: I know the article seems really long but thats because I tried to explain each and every thing we will be doing throughout this tutorial

TOC:


Step 1: Creating the project.

Use the following command to get started:
$ npx create-react-app chitchat
Now, I used the name chitchat for my project but, you can use any name you like.

Step 2: Installing necessary modules

We'll be using the following modules in our project:

  • firebase -> allows us to use firebase in our project
  • react-firebase-hooks -> allows us to get data from our database in real time
  • tailwindcss [Optional] -> for styling our chat app

To install them, we need to first cd into our newly created project and then use the following command:
$ npm install firebase react-firebase-hooks
Optionally, install tailwindcss:
$ npm install tailwindcss

Step 3: Setting up firebase

Our project now is all set up! But, we need to have somewhere to store the chats. That's where firebase comes in! We can store the chats and host our chat app with firebase.

Let's start by creating a new project at Firebase Console

Add a name for your project and you can enable analytics if you wish. Your should now see a screen like this after your project is created:

Firebase Console

Now, let's enable authentication to let users sign in with their google account. Click on the authentication tab on the sidebar and enable Google authentication.

Once the auth is set up, we need to set up a database for our project. Click on the Cloud Firestore tab in the sidebar and create a database.

Firebase Firestore Menu

Next, we need to edit the database rules so that only logged in users can chat. In the rules tab paste the following code:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if false;
    }

    match /messages/{docID} {
        allow read: if request.auth.uid != null;
      allow create: if canCreateMessage();
    }

    // custom func to check if the user can send messages
    function canCreateMessage() {
        let isSignedIn = request.auth.uid != null;
      let isOwner = request.auth.uid == request.resource.data.uid;

      return isSignedIn && isOwner;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Database Rules

Now that our database is completely set up, we can work on the app interface now!

Step 4: Creating functions for the chat

We'll be working only with the App.js file, present in src directory of our project, so load that up in your favorite text editor.

We'll begin by importing all the necessary functions.

import React, { useEffect, useRef, useState } from 'react';

import firebase from 'firebase/app';
import 'firebase/firestore';
import 'firebase/auth';

import { useAuthState } from 'react-firebase-hooks/auth';
import { useCollectionData } from 'react-firebase-hooks/firestore';
Enter fullscreen mode Exit fullscreen mode

Next, we need to add our firebase config which you can get from project settings by adding a web app as shown below:

Creating web app in firebase and getting config values

Add the config values to App.js:

firebase.initializeApp({
  apiKey: "AIzaSyAmQZaUtO_0LZ3b6-7r5VIQhPHW2z1iqxk",
  authDomain: "chitchat-aa31b.firebaseapp.com",
  databaseURL: "https://chitchat-aa31b.firebaseio.com",
  projectId: "chitchat-aa31b",
  storageBucket: "chitchat-aa31b.appspot.com",
  messagingSenderId: "544785049624",
  appId: "1:544785049624:web:5900f7045eea337b573b6d"
})
Enter fullscreen mode Exit fullscreen mode

Lastly, we'll define auth and firestore variable to use in our project:

const auth = firebase.auth();
const firestore = firebase.firestore();
Enter fullscreen mode Exit fullscreen mode

Step 5: Functions & Components

We'll start with App():

function App() {
  // checks if user is authenticated i.e. logged in
  const [user] = useAuthState(auth);

  return (
    <div>
      <SignOut />
      <section>
        {/* Shows chatroom if user is logged in
        else show signin page */}
        {user ? <ChatRoom /> : <SignIn />}
      </section>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Then, we'll define a sign-in function for our chat app with google auth.

function SignIn() {
  const signInWithGoogle = () => {
    const provider = new firebase.auth.GoogleAuthProvider();
    auth.signInWithPopup(provider);
  }
  return (
    <div>
      <button onClick={signInWithGoogle}>Sign In With Google</button>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

While we are at it, let's also include a sign-out function.

function SignOut() {
  return auth.currentUser && (
    <div>
      <button onClick={() => auth.signOut()}>Sign Out</button>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

Now comes the main part of our chat app, the chat room where users can post messages.

function ChatRoom() {
  // we will use this to scroll to bottom of chat on page-reload and after sending a message
  const dummy = useRef();
  const scrollToBottom = () => {
    dummy.current.scrollIntoView({ behavior: 'smooth' });
  }

  // getting the message and sorting them by time of creation
  const messagesRef = firestore.collection('messages');
  const query = messagesRef.orderBy('createdAt', 'asc').limitToLast(25);

  const [messages] = useCollectionData(query, {idField: 'id'});

  return (
    <div>
      <div>
        {/* we will loop over the message and return a
        ChatMessage component for each message */}
        {messages && messages.map(msg => <ChatMessage key={msg.id} message={msg} />)}
        <span ref={dummy}></span>
      </div>

      {/* Form to type and submit messages */}
      <form onSubmit={sendMessage}>
        <input value={formValue} onChange={(e) => setFormValue(e.target.value)} placeholder="Say something" />
        <button type="submit" disabled={!formValue}>send</button>
      </form>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

Let's define our sendMessage function now!

const sendMessage = async (e) => {
    e.preventDefault();
    // gets name, userID and pfp of logged in user
    const { displayName, uid, photoURL } = auth.currentUser;

    await messagesRef.add({
      user: displayName,
      body: formValue,
      createdAt: firebase.firestore.FieldValue.serverTimestamp(),
      uid: uid,
      photoURL: photoURL
    })

    // resetting form value and scrolling to bottom
    setFormValue('');
    dummy.current.scrollIntoView({ behavior: 'smooth' });
  }
Enter fullscreen mode Exit fullscreen mode

Now, the last thing for us is to define the ChatMessage component that will display the Chat messages.

function ChatMessage(props) {
  const { user, body, uid, photoURL, createdAt } = props.message;

    return (
        <div>
            <img src={photoURL || 'https://i.imgur.com/rFbS5ms.png'} alt="{user}'s pfp" />
        </div>
        <div>
            <p>{user}</p>
            <p>{body}</p>
      </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

Aaaaaand with that, our chat app is officially done! All that's left is to add css-styling to your content. You can then deploy the app to firebase using the following command:
$ firebase init hosting && firebase deploy --only hosting

Checkout the chat app in action and here's the repo for the project:

GitHub logo pranshuj73 / chitchat

Chat app made with create-react-app and firebase.


If you made it this far, kudos to you! If you have any tips or suggestions, please leave them down in the comments.

Discussion (4)

Collapse
dmk1111 profile image
dmk1111

I'd suggest you removing API keys from code examples and public repos.
Great article, anyway!

Collapse
pranshuj73 profile image
Pranshu Jha Author

Glad you found the article useful! πŸ˜„
About the api keys, I did delete the app after making the tutorial, so the api keys are invalid and, as for the repo I was careful not to push the api keys (or atleast I think so πŸ˜…)

Collapse
aaronksaunders profile image
Aaron K Saunders

you basic cut and pasted this code from somewhere else?

fireship.io/lessons/react-firebase...

Collapse
pranshuj73 profile image
Pranshu Jha Author

wasnt a cut and paste, but yes, you can say this is a copy of fireship's app