Notifications keep users informed and engaged. A custom React notification center lets you control and tailor the user experience fully. Here’s a concise guide to building one from scratch, covering both frontend and backend components for real-time updates.
1. Requirements for a React Notification Center
- Real-Time Updates: Notifications should appear instantly without refreshing.
- Background Notifications: Use service workers to handle notifications even when the app is not in focus.
- Multi-Channel Support: Include in-app notifications, push notifications, emails, and SMS.
- User Preferences: Allow users to customize their notification settings.
- Scalability: Ensure the system can handle a high volume of notifications.
- Reliability: Notifications must be delivered accurately and promptly.
2. System Architecture Overview
Frontend
- React App: Displays notifications and handles real-time updates.
- Service Worker: Manages background notifications via the Notifications API.
- WebSocket/ Polling: Keeps the notification feed updated in real-time.
Backend
-
Microservices:
- Notification Service: Generates and stores notifications.
- Dispatch Service: Sends notifications to various channels.
- User Preferences Service: Manages user settings for notifications.
- Message Queue: Efficiently handles notification distribution.
- Database: Stores user preferences and notification logs.
- Push Services: Integrate with Firebase and APNs for push notifications.
3. Backend Architecture
3.1. Microservices Design
Microservice | Functionality |
---|---|
Notification Service | Generates and stores notifications |
Dispatch Service | Sends notifications to different channels |
User Preferences Service | Manages user settings and preferences |
3.2. Database Design
- Notifications Table: Stores notification metadata.
- User Preferences Table: Tracks user settings.
- Logs Table: Keeps a record of all notifications sent.
Example: Notification Service in Node.js/Express
const express = require('express');
const app = express();
let notifications = [];
app.post('/notify', (req, res) => {
const notification = {
id: notifications.length + 1,
type: req.body.type,
message: req.body.message,
userId: req.body.userId,
status: 'unread',
timestamp: new Date()
};
notifications.push(notification);
res.status(200).send(notification);
});
app.listen(3000, () => {
console.log('Notification Service running on port 3000');
});
4. Real-Time Communication
4.1. WebSocket Connection
- Server: Handles connections and broadcasts notifications.
- Client: Listens for updates and updates the UI in real-time.
Example: WebSocket Server with Socket.IO
const io = require('socket.io')(3001);
io.on('connection', (socket) => {
console.log('User connected:', socket.id);
socket.emit('notification', {
message: 'New notification!',
timestamp: new Date()
});
socket.on('disconnect', () => {
console.log('User disconnected:', socket.id);
});
});
Client-Side Integration in React
import React, { useEffect, useState } from 'react';
import io from 'socket.io-client';
const socket = io('http://localhost:3001');
function NotificationCenter() {
const [notifications, setNotifications] = useState([]);
useEffect(() => {
socket.on('notification', (notification) => {
setNotifications(prev => [...prev, notification]);
});
}, []);
return (
<div>
<h2>Notification Center</h2>
{notifications.map((notif, index) => (
<div key={index}>{notif.message} - {notif.timestamp}</div>
))}
</div>
);
}
export default NotificationCenter;
4.2. Polling as a Fallback
- Client: Periodically checks the server for new notifications.
Example: Polling Implementation in React
import React, { useEffect, useState } from 'react';
function NotificationCenter() {
const [notifications, setNotifications] = useState([]);
useEffect(() => {
const interval = setInterval(() => {
fetch('/api/notifications')
.then(response => response.json())
.then(data => setNotifications(data));
}, 5000); // Poll every 5 seconds
return () => clearInterval(interval);
}, []);
return (
<div>
<h2>Notification Center</h2>
{notifications.map((notif, index) => (
<div key={index}>{notif.message}</div>
))}
</div>
);
}
export default NotificationCenter;
5. Integrating Notifications API and Service Workers
5.1. Service Workers
- Register: Handle background notifications.
Example: Registering a Service Worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js').then(registration => {
console.log('Service Worker registered:', registration.scope);
}).catch(error => {
console.error('Service Worker registration failed:', error);
});
}
5.2. Notifications API
- Permission Handling: Request permission to display notifications.
- Trigger Notifications: Show notifications even when the app isn’t active.
Example: Displaying a Notification
if (Notification.permission === 'granted') {
new Notification('New message!', {
body: 'Click to view the message.',
icon: '/path/to/icon.png'
});
} else if (Notification.permission !== 'denied') {
Notification.requestPermission().then(permission => {
if (permission === 'granted') {
new Notification('New message!', {
body: 'Click to view the message.',
icon: '/path/to/icon.png'
});
}
});
}
6. Push Notifications with Firebase and APNs
6.1. Firebase Cloud Messaging (FCM)
- Setup: Register with Firebase and get tokens.
- Send Notifications: Use tokens to dispatch notifications.
Example: Sending Push Notifications with FCM in Node.js
const admin = require('firebase-admin');
const serviceAccount = require('./path/to/serviceAccountKey.json');
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
});
const message = {
notification: {
title: 'New Notification',
body: 'You have a new notification!'
},
token: 'device-token'
};
admin.messaging().send(message)
.then(response => console.log('Message sent:', response))
.catch(error => console.error('Error sending message:', error));
6.2. Apple Push Notification service (APNs)
- Integrate: Handle device tokens and use them to send notifications via APNs.
7. Building the Notification Center UI in React
7.1. Designing the Notification Feed
- Notification List: Show all notifications with options to mark as read or delete.
- Notification Badge: Display unread notification count.
-
Toast Notifications: Use libraries like
react-toastify
for brief notifications.
Example: Notification List Component
import React from 'react';
function NotificationList({ notifications }) {
return (
<div>
{notifications.map(notification => (
<div key={notification.id}>{notification.message}</div>
))}
</div>
);
}
export default NotificationList;
Example: Toast Notifications with react-toastify
import { toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
toast.configure();
function notify() {
toast('New notification!', { position: toast.POSITION.BOTTOM_RIGHT });
}
notify();
7.2. Managing State with Redux or Context API
- Global Store: Use Redux or Context API to manage notifications globally.
- Real-Time Updates: Update the store with new notifications via WebSocket or polling.
Example: Managing State with Redux
import { createSlice } from '@reduxjs/toolkit';
const notificationSlice = createSlice({
name: 'notifications',
initialState: [],
reducers: {
addNotification: (state, action) => {
state.push(action.payload);
},
markAsRead: (state, action) => {
const notification = state.find(n => n.id === action.payload);
if (notification) {
notification.read = true;
}
}
}
});
export const { addNotification, markAsRead } = notificationSlice.actions;
export default notificationSlice.reducer;
As a good dev, you should go on to build the notification system in react from scratch, but, if your boss needs it ASAP and you’ve got a vacation planned (or just really need a break), check out my tool. It simplifies everything and gives you ready-to-use components as your new notifications API, available in all popular SDK. So you can chill while we handle the infra! 🌴🚀