This content originally appeared on DEV Community and was authored by Prasanna Vijayan
Say Goodbye to Prop Drilling & Context!
Introduction
Every React app needs notificationsβwhether it’s a success message, an error alert, or a warning toast. But how do we manage notifications globally without Redux, Context, or prop drilling?
The answer: The Publish-Subscribe (Pub-Sub) Pattern!
In this post, we’ll build a notification system that:
Uses Pub-Sub instead of Context or Redux
Works globally without prop drilling
Automatically dismisses notifications
Stacks notifications on top of each other
What is the Pub-Sub Pattern?
The Publish-Subscribe (Pub-Sub) Pattern is a messaging system where:
Publishers send out events.
Subscribers listen for those events and react accordingly.
This makes it perfect for notifications because any part of the app can trigger an event, and the notification system will handle it automaticallyβwithout requiring direct dependencies!
Step 1: Create an Event Bus (Pub-Sub Utility)
Since JavaScript lacks a built-in Pub-Sub system, we’ll create a lightweight event bus.
Create a new file: eventBus.js
const eventBus = {
events: {},
subscribe(eventName, callback) {
if (!this.events[eventName]) {
this.events[eventName] = [];
}
this.events[eventName].push(callback);
// Return unsubscribe function
return () => {
this.events[eventName] = this.events[eventName].filter(fn => fn !== callback);
};
},
publish(eventName, data) {
if (this.events[eventName]) {
this.events[eventName].forEach(callback => callback(data));
}
}
};
export default eventBus;
How This Works:
subscribe(eventName, callback): Adds a listener for an event.
publish(eventName, data): Triggers all callbacks listening to an event.
Returns an unsubscribe function so we can clean up listeners when needed.
Step 2: Create the Notification List Component
The NotificationList will:
Listen for notify events from the eventBus
Store notifications in local state
Automatically remove notifications after 3 seconds
Create a new file: NotificationList.js
import React, { useState, useEffect } from "react";
import eventBus from "./eventBus";
import "./Notifications.css";
const NotificationList = () => {
const [notifications, setNotifications] = useState([]);
useEffect(() => {
// Subscribe to "notify" event
const unsubscribe = eventBus.subscribe("notify", (notification) => {
const id = Date.now();
setNotifications((prev) => [...prev, { id, ...notification }]);
// Auto-remove notification after 3 seconds
setTimeout(() => {
setNotifications((prev) => prev.filter((n) => n.id !== id));
}, 3000);
});
return () => unsubscribe(); // Cleanup on unmount
}, []);
return (
<div className="notifications-container">
{notifications.map((notif) => (
<div key={notif.id} className={`notification ${notif.type}`}>
{notif.message}
</div>
))}
</div>
);
};
export default NotificationList;
Step 3: Add Some Styles for Notifications
Create a new file: Notifications.css
.notifications-container {
position: fixed;
top: 20px;
right: 20px;
display: flex;
flex-direction: column;
gap: 10px;
z-index: 1000;
}
.notification {
padding: 10px 15px;
color: white;
font-weight: bold;
border-radius: 5px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
opacity: 0.9;
animation: fade-in 0.3s ease-in-out;
}
.notification.success {
background-color: green;
}
.notification.failure {
background-color: red;
}
.notification.warning {
background-color: orange;
}
@keyframes fade-in {
from {
transform: translateY(-10px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
Step 4: Use It in the App Component
Now, let’s wire it all together by publishing notifications when buttons are clicked.
Modify App.js
import React from "react";
import eventBus from "./eventBus";
import NotificationList from "./NotificationList";
const App = () => {
const notify = (type, message) => {
eventBus.publish("notify", { type, message });
};
return (
<div>
<h2>Notification System (Pub-Sub Pattern)</h2>
<button onClick={() => notify("success", "Success!")}>Success</button>
<button onClick={() => notify("failure", "Failure!")}>Failure</button>
<button onClick={() => notify("warning", "Warning!")}>Warning</button>
<NotificationList />
</div>
);
};
export default App;
How Everything Works Together
1⃣ Click a button β eventBus.publish(“notify”, { type, message })
2⃣ NotificationList listens for “notify” events
3⃣ Notification appears in the UI
4⃣ After 3 seconds, the notification auto-disappears
Final Thoughts: Why Use Pub-Sub?
Using Pub-Sub in React is powerful because:
No Context or Redux needed β Clean & lightweight
Fully decoupled β Components donβt need to know about each other
Scalable β Can be extended to support WebSockets, logging, and more
Next Steps
Want to take this further? Try adding:
A close button to manually remove notifications
Animated entry/exit effects
Persistent notifications that stay until dismissed
Now go and implement this in your projects! Happy coding!
This content originally appeared on DEV Community and was authored by Prasanna Vijayan