Piggy Backing on ReactJS’s ServiceWorker for Notification Event Listeners

About a week ago I decided to start learning ReactJS because why not? just to get some exposure to yet another javascript framework that seems to be pretty popular right now. I had been in the middle of putting together a notification/reminder web app (more on that in a later post) and wasn’t particularly happy with the code I ended up putting together to populate the UI. Fast forward to yesterday, I gained some rudimentary knowledge on how to use React, converted my existing jquery based web app to React (along with my ServiceWorker code that was detecting when a notification was clicked or closed) and I was now ready to do a production build of the app. Upon doing the build and testing the resulting site, I found out that my service worker code was no longer firing.

After doing some digging I found out that React uses its own service worker to enable itself to run when your browser or device is offline. I was thrilled that I got that for free out of the box, but it also meant that my service worker was no longer running since you can only have 1 service worker running at a time for a single URL scope.

My solution for this was to merge my service worker code in with React’s service worker. Just a warning: This may not be recommended by React, and it might only work for my particular case because I just need to add some event listeners to the service worker. Your mileage may vary.

Since I was no longer able to run any code during the register phase of the service worker (since React is doing the registration), I needed to do the following in order to get a reference to the registration object whenever I want to call showNotification()



navigator.serviceWorker.ready.then(registration => {
    registration.showNotification("Notification Text",
    {
        data: {
            id: "recordid"
        }
    });
});

On the service worker side, I just need to paste in my event listeners into the service-worker.js file in the /build directory after building the React project. Keep in mind, you will need to do this every time you re-build your React project since that file will get replaced.



self.addEventListener("notificationclick", handleClickClose)
self.addEventListener("notificationclose", handleClickClose)

function handleClickClose(event) {
    const n = event.notification;
    sendMessage(n.data.id)
    n.close();
}

And thats all there is to it! You might notice that I’m calling a method sendMessage() in my event handler. I’m using this to let my application know which notification is being acted on. It isn’t required for the event handler to work, but it is part of the functionality for the web app I’m working on. sendMessage() is implemented as follows:



function sendMessage(pstrMessage)
{
    clients.matchAll({includeUncontrolled: true, type: 'window'}).then(clients => {
        clients.forEach(client => {
            client.postMessage(pstrMessage)
        })
    })
}

And I have an event listener that is registered during componentDidMount() in my React app’s root class that listens for messages from the service worker:


navigator.serviceWorker.addEventListener('message', function(event){
     // do some work here
     console.log("click notification for " + event.data)
});

Just one final note, I wrapped the registration of my original service worker in an if statement that checks if I’m in dev mode or not. This way it will still register during development (since the React service worker isn’t registered) and it is prevented from registering in production.



if (window.location.port === "3000")
{
     navigator.serviceWorker.register('/sw.js').then(...)
}

I imagine if I was better versed in React and building npm packages that there might be some way to bundle this up into a cleaner package that would make it more reusable and tie into the React build process in order to skip the manual step of copy/pasting the event listeners into the service-worker.js file. If anyone stumbles on this article and has knowledge of how to do that please let me know!

Leave a Reply

%d bloggers like this: