Push Notifications with Firebase in React.js
Tags: javascript, firebase
Published: 2021-12-01 22:29:32

<h3>Introduction</h3><p>Push notifications are <strong>alerts that are "pushed" to a user's device by apps, even when those apps aren't open</strong>. In the case of web push notifications, the web app receives messages pushed to it from a server at any time. This includes when the application is active or inactive or not open in the browser and when the browser is inactive. Firebase Cloud Messaging is a cross-platform messaging solution that lets you reliably send these messages at no cost.</p><p>In this tutorial, we are going to be walking through how to set up Firebase Cloud Messaging to receive web push notifications in your React.js app.</p><p></p><h3>Firebase Setup</h3><p>Create an account at <a href="https://firebase.google.com">https://firebase.google.com</a>, if you don't already have one. Upon successful account creation, you would be navigated to <a href="https://console.firebase.google.com">https://console.firebase.google.com</a> afterwards, where you can create a project by clicking on the <strong>Create a project</strong> button and filling out the necessary fields.</p>![Firebase Setup Image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dkqkweuh7c7xqqno1mgw.png)
<p>Once project creation is done. Click on the created project and select the platform you want to connect the service to. Since we are working on a web project we can select the <b>web</b> option by clicking on the (<strong></></strong>) icon. This would take us to an interface to <strong>Add Firebase to your web app. </strong>After filling in the field for <strong>app nickname</strong> and clicking the<strong> Register app </strong>button, it should generate a configuration object that we'll need to pass to our React app in later steps.</p>
![Firebase Setup Image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wff49kjoiawnz7s8k2ac.png)
![Firebase Setup GIF](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/voct5qvoz2zc6p0am9mx.gif)

</br><h3>Connecting Firebase Cloud Messaging to our Application</h3><p>1. Install Firebase in your React project by running:
```
npm install firebase
```
</p>

<p>2. Create a new file called <code>firebase.js</code> and add the following lines of code :</p>

```javascript
import { initializeApp } from 'firebase/app';

// Replace this firebaseConfig object with the configurations for the project you created on your firebase console. 
var firebaseConfig = {
 //... 
};

initializeApp(firebaseConfig);
```
<p>3. Import Firebase's messaging module into the <code>firebase.js</code> file:</p>

```javascript
import { getMessaging } from "firebase/messaging";

//...

const messaging = getMessaging();

```
<p>4. Create a function called <code>requestForToken</code> that makes use of Firebase's <a href="https://firebase.google.com/docs/reference/js/messaging_#gettoken"><code>getToken</code></a> method. This lets you subscribe your app to push notifications. If notification permission has not been granted, this method will ask the user for notification permissions. Otherwise, it returns a token or rejects the promise due to an error.</p>
```javascript
//....
import { getMessaging, getToken} from 'firebase/messaging';

//....

export const requestForToken = () =>; {
  return getToken(messaging, { vapidKey: REPLACE_WITH_YOUR_VAPID_KEY })
    .then((currentToken) =>; {
      if (currentToken) {
        console.log('current token for client: ', currentToken);
        // Perform any other necessary action with the token
      } else {
        // Show permission request UI
        console.log('No registration token available. Request permission to generate one.');
      }
    })
    .catch((err) =>; {
      console.log('An error occurred while retrieving token. ', err);
    });
};
```
<p><strong>Note</strong>: The <code>getToken</code> method requires you to pass a <em>Voluntary Application Server Identification</em> or <em>VAPID</em> key. You can get it by following these steps:</p><ul><li>Click on <strong>Project Settings</strong><em> </em>for your project from the Firebase console, then navigate to the <strong>Cloud Messaging</strong> tab and scroll to the <strong>Web configuration</strong> section. </li><li>Under <strong>Web Push certificates</strong> tab, click on <strong>Generate key pair</strong>. </li></ul>


<p>5. Finally, you can link the <code>firebase.js</code> file to the rest of your project by importing it where it's needed. In this case, we can create a <code>Notification</code> component:</p>
```javascript
import React from 'react';
import { requestForToken } from './firebase';

const Notification = () =>; {
 requestForToken();
 //....
}
```
</br>
<h4>Additional Step: </h4><p>The messaging service requires a <code>firebase-messaging-sw.js</code> file to work fine. I'll explain more about this file in the <strong>Background Listener Setup </strong>section of this guide. For now, create an empty file named <code>firebase-messaging-sw.js</code> in the public folder of your project.</p><p>Navigate to the browser console of your app to test if our app can connect to Firebase Cloud Messaging service. You should see the token that was received, if successful.![firebase-push-notification-image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9f098j2aceg3n9yffahi.png) </p>

</br>
<h4>Something went wrong?</h4><p>1.) If you got an error concerning <em><strong>permissions not being granted but blocked instead</strong></em>, you should make sure you set notifications permissions to <em><strong>Allow</strong></em> in your browser.
![firebase-push-notification-image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kr5b905l5ddbuovlojua.png)</p>
<p>2.) If you got an error concerning a <em><strong>missing required authentication credential</strong>, </em>then you probably passed the wrong <strong>VAPID_KEY</strong>.</p>
![firebase-push-notification-image
![firebase-push-notification-image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wd52pv94dphzsm2lwrxc.png)](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dv6f6fao1kjqcj401crn.png)


</br>

<h3>Receiving Messages</h3><p>Now that the initial setup is done, you'll need to configure message listeners. Foreground message listeners are called when the page has focus(i.e. when the user is on the browser tab containing our web app), while background message listeners are called when the user is on a different tab or even when the tab containing our app is closed.</p><h4>Foreground Listener Setup</h4><p>To handle messages when the app is in the foreground, you can make use of Firebase's <code><a href="https://firebase.google.com/docs/reference/js/messaging_#onmessage">onMessage</a></code> method in your <code>firebase.js</code> file:</p>

```javascript
import { getMessaging, getToken, onMessage } from 'firebase/messaging';
//......
const messaging = getMessaging();
//......
export const onMessageListener = () =>;
  new Promise((resolve) =>; {
    onMessage(messaging, (payload) =>; {
      console.log("payload", payload)
      resolve(payload);
    });
  });
```

<p>You can then call the method in the <code>Notification</code> component. For this tutorial, I'm making use of <a href="https://react-hot-toast.com/"><em>react-hot-toast</em></a> library to create a toast UI for displaying the notification details received from the message listener.</p>
```javascript
import React, {useState, useEffect} from 'react'
import toast, { Toaster } from 'react-hot-toast';
import { requestForToken, onMessageListener } from './firebase';

const Notification = () =>; {
  const [notification, setNotification] = useState({title: '', body: ''});
  const notify = () => toast(<ToastDisplay/>);
  function ToastDisplay() {
    return (
      <div>
        <p><b>{notification?.title}</b></p>
        <p>{notification?.body}</p>
      </div>
    );
  };

  useEffect(() => {
    if (notification?.title ){
     notify()
    }
  }, [notification])

  requestForToken();

  onMessageListener()
    .then((payload) => {
      setNotification({title: payload?.notification?.title, body: payload?.notification?.body});     
    })
    .catch((err) => console.log('failed: ', err));

  return (
     <Toaster/>
  )
}

export default Notification
```
<p></p><h4>Background Listener Setup</h4><p>To handle background messages, you'd need to make use of a <strong>service worker</strong>. A service worker is a script that your browser runs in the background, separate from the web page, enabling features that do not require a web page or user interaction.</p><p>You can go ahead to add the following lines of code to your <code>firebase-messaging-sw.js</code> file :</p>

```javascript
// Scripts for firebase and firebase messaging
importScripts('https://www.gstatic.com/firebasejs/8.2.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/8.2.0/firebase-messaging.js');

// Initialize the Firebase app in the service worker by passing the generated config
const firebaseConfig = {
  apiKey: `REPLACE_WITH_YOUR_FIREBASE_MESSAGING_API_KEY`,
  authDomain: `REPLACE_WITH_YOUR_FIREBASE_MESSAGING_AUTH_DOMAIN`,
  projectId: `REPLACE_WITH_YOUR_FIREBASE_MESSAGING_PROJECT_ID`,
  storageBucket: `REPLACE_WITH_YOUR_FIREBASE_MESSAGING_STORAGE_BUCKET`,
  messagingSenderId: `REPLACE_WITH_YOUR_FIREBASE_MESSAGING_SENDER_ID`,
  appId: `REPLACE_WITH_YOUR_FIREBASE_MESSAGING_APP_ID`,
  measurementId: `REPLACE_WITH_YOUR_FIREBASE_MESSAGING_MEASUREMENT_ID`,
};

firebase.initializeApp(firebaseConfig);

// Retrieve firebase messaging
const messaging = firebase.messaging();

messaging.onBackgroundMessage(function(payload) {
  console.log('Received background message ', payload);
 // Customize notification here
  const notificationTitle = payload.notification.title;
  const notificationOptions = {
    body: payload.notification.body,
  };

  self.registration.showNotification(notificationTitle,
    notificationOptions);
});
```
<h3>Testing Notifications</h3><p>To test whether the notifications are functional, you can trigger a test notification from the firebase console with the following steps:</p><ul><li>On your project dashboard, scroll to the <strong>Cloud Messaging </strong>section.</li><li>Under the <strong>Notifications</strong> tab, click on the <strong>New notification </strong>button</li><li>Fill in the information for <strong>Notification title</strong> and <strong>Notification text</strong></li><li>Under the <strong>Device preview</strong> section, click on <strong>Send test message</strong></li><li>In the popup that opens, enter the <strong>client token</strong> that is logged in the console as the FCM registration token and press the <strong>+</strong> button</li><li>Make sure that the FCM token is checked and click on <strong>Test</strong>. You could also decide to fill in the entire<strong> Compose notification</strong> section and press the <strong>Review</strong> button at the bottom of the page to have it sent to multiple target apps.</li></ul><p>If you're on the browser tab with the app opened, you should see a notification pop up. </p>![firebase-push-notification-image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/86k1tryby1shaq5i5g78.png)<br /><p>While if the browser tab with the application isn't in focus, you should see a default system notification pop-up.</p>
![firebase-push-notification-image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hvusgoz1bmrto727fm9t.png)<br /><p><strong>Note:</strong> To see a notification banner when notifications are received in the background, make sure to turn on the feature for your browser under your system's notification settings.</p>
![firebase-push-notification-image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/67vd8osmwt7lire8rv4u.png)<br /><h3></h3><h4>Something went wrong ?</h4><p>There may be cases where a user doesn't get notifications immediately or at all. This can be due to a variety of reasons, some of which are covered <a href="https://www.pushengage.com/why-your-web-push-notification-lower-reach-than-expected/">here</a>.</p><h4>Repository Code</h4><p> You can find the GitHub repo for this tutorial at <a href="https://github.com/AudreyHal/React-Firebase-Cloud-Messaging-Demo">https://github.com/AudreyHal/React-Firebase-Cloud-Messaging-Demo</a></p>