Have you ever wanted to stream data to your ReactJS app in real time? Maybe show a popup message or shut down the app completely without waiting for a polling solution?
As it turns out, the solution existed since around 2010 and is now fully supported in all major browsers.
Let’s explore Server-Sent Events (SSE), compare them to other real-time data solutions, and implement a robust example using a modern ReactJS app created with Vite.
Overview of Real-Time Data Solutions
When talking about real-time data solutions for ReactJS (or any other JS application), we have a few options:
- Polling (not really real-time)
- Long-Polling
- WebSockets
- Server-Sent Events (SSE)
Here’s how they compare:
Feature/Criteria | Polling | Long-Polling | WebSockets | Server-Sent-Events (SSE) |
---|---|---|---|---|
Real-Time | No (delay due to interval) | Yes (semi-real-time) | Yes (true real-time) | Yes (true real-time) |
Ease of Implementation | Yes (simple) | Yes (moderately simple) | No (requires more setup) | Yes (built-in browser support) |
Browser Support | Yes (all browsers) | Yes (all browsers) | Yes (modern browsers) | Yes (modern browsers) |
Efficiency | No (constant requests) | No (open connections) | Yes (optimized for real-time) | Yes (low overhead) |
Bi-Directional Communication | No (client-to-server only) | No (client-to-server only) | Yes (full-duplex) | No (server-to-client only) |
Reconnection Handling | No (manual logic) | Yes (built-in retry) | No (manual logic) | Yes (auto-reconnect by default) |
Use Case Examples | Periodic updates (e.g., refreshing feeds) | Semi-real-time notifications | Chat apps, live games | Real-time notifications, stock tickers |
If your use case involves getting events from the server only, SSE is a simple, efficient, and reliable solution.
Backend Implementation
We’ll use an Express.js server for the backend. Follow these steps:
Basic Express Setup
Start with a basic Express server:
const express = require('express');
const app = express();
const PORT = 3010;
app.use(express.json());
app.get('/events', (req, res) => {
res.status(200).send('Event route is working');
});
app.listen(PORT, () => {
console.log(`SSE server running on http://localhost:${PORT}`);
});
Adding SSE-Specific Headers
Add headers to enable SSE:
app.get('/events', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
res.write(`data: Connected to SSE\n\n`);
});
Sending Periodic Messages
Send updates periodically to connected clients:
app.get('/events', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
res.write(`data: Connected to SSE\n\n`);
const interval = setInterval(() => {
const message = { time: new Date().toISOString() };
res.write(`data: ${JSON.stringify(message)}\n\n`);
}, 2000);
req.on('close', () => {
clearInterval(interval);
res.end();
});
});
Enabling CORS
To avoid cross-origin issues, add:
const cors = require('cors');
app.use(cors());
Frontend Implementation Using Vite and ReactJS
Setting Up the Project
Create a new Vite project with ReactJS and TypeScript:
npm create vite@latest sse -- --template react-ts
cd sse
npm install
Setting Up the Component
Edit the App.tsx file to include useEffect and useState hooks:
import { useEffect, useState } from "react";
import "./App.css";
function App() {
const [messages, setMessages] = useState("");
useEffect(() => {
const eventSource = new EventSource("http://localhost:3010/events");
eventSource.onmessage = (event) => {
console.log("Received event:", event.data);
setMessages(event.data);
};
eventSource.onerror = (error) => {
console.error("EventSource failed:", error);
};
return () => {
eventSource.close();
};
}, []);
return (
<div>
<h1>Real-Time Messages</h1>
<p>{messages}</p>
</div>
);
}
export default App;
Advanced Topics
Security Considerations
- Authentication: Secure your SSE endpoint using tokens:
app.get('/events', authenticate, (req, res) => { ... });
-
Rate Limiting: Use middleware like
express-rate-limit
to prevent abuse.
Scaling SSE
- Load Balancers: Use NGINX or HAProxy to efficiently manage SSE connections.
- Connection Limits: Implement logic to cap active connections for better scalability.
Debugging SSE
- Use
curl
to test your endpoint:
curl http://localhost:3010/events
- Monitor browser DevTools for network activity and messages.
Custom Event Types
SSE supports custom event types using the event:
keyword:
res.write(`event: customEvent\n`);
res.write(`data: {"info": "custom event triggered"}\n\n`);
Handle them on the frontend:
eventSource.addEventListener('customEvent', (event) => {
console.log('Custom Event:', event.data);
});
Conclusion
With Vite and ReactJS as the frontend framework and a lightweight Express backend, we’ve implemented a robust, scalable real-time solution using Server-Sent Events. The combination of simplicity, efficiency, and modern browser support makes SSE an excellent choice for unidirectional real-time data delivery.
Top comments (0)