Streaming live data to your ReactJS app using Server-Side-Events

Streaming live data to your ReactJS app using Server-Side-Events


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-Side-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}`);
});
Enter fullscreen mode

Exit fullscreen mode



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 SSEnn`);
});
Enter fullscreen mode

Exit fullscreen mode



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 SSEnn`);

    const interval = setInterval(() => {
        const message = { time: new Date().toISOString() };
        res.write(`data: ${JSON.stringify(message)}nn`);
    }, 2000);

    req.on('close', () => {
        clearInterval(interval);
        res.end();
    });
});
Enter fullscreen mode

Exit fullscreen mode



Enabling CORS

To avoid cross-origin issues, add:

const cors = require('cors');
app.use(cors());
Enter fullscreen mode

Exit fullscreen mode




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
Enter fullscreen mode

Exit fullscreen mode



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;
Enter fullscreen mode

Exit fullscreen mode



Advanced Topics



Security Considerations

  1. Authentication: Secure your SSE endpoint using tokens:
app.get('/events', authenticate, (req, res) => { ... });
Enter fullscreen mode

Exit fullscreen mode

  1. Rate Limiting: Use middleware like express-rate-limit to prevent abuse.



Scaling SSE

  1. Load Balancers: Use NGINX or HAProxy to efficiently manage SSE connections.
  2. Connection Limits: Implement logic to cap active connections for better scalability.



Debugging SSE

  1. Use curl to test your endpoint:
curl http://localhost:3010/events
Enter fullscreen mode

Exit fullscreen mode

  1. Monitor browser DevTools for network activity and messages.



Custom Event Types

SSE supports custom event types using the event: keyword:

res.write(`event: customEventn`);
res.write(`data: {"info": "custom event triggered"}nn`);
Enter fullscreen mode

Exit fullscreen mode

Handle them on the frontend:

eventSource.addEventListener('customEvent', (event) => {
  console.log('Custom Event:', event.data);
});
Enter fullscreen mode

Exit fullscreen mode




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.



Source link
lol

By stp2y

Leave a Reply

Your email address will not be published. Required fields are marked *

No widgets found. Go to Widget page and add the widget in Offcanvas Sidebar Widget Area.