Resources
Aug 20, 2024

Utilisation d'EventSource avec Node.js et React Query

Afficher les mises à jour du back instantanément dans votre app React

Utilisation d'EventSource avec Node.js et React Query

Introduction

Lorsqu'il s'agit de mettre en place des mises à jour en temps réel dans une application web, deux technologies se distinguent : WebSockets et EventSource (Server-Sent Events). Bien que WebSockets fournisse une connexion bidirectionnelle, EventSource est souvent un choix plus simple et efficace pour des flux de données unidirectionnels (du serveur vers le client). EventSource est également plus facile à implémenter, fonctionne nativement avec les navigateurs sans bibliothèque supplémentaire, et gère automatiquement les reconnections en cas de défaillances du réseau. Dans cet article, nous allons explorer comment implémenter EventSource à la fois sur le backend avec Node.js et sur le frontend avec React Query.

Le code présenté est volontairement naïf afinc de vous montrer rapidement comment implémenter. A vous d'adapter cela à votre propre architecture.

Configuration du Backend avec Node.js

Commencez par installer Express.js :

npm install express

Ensuite, créez un serveur Node.js pour envoyer des événements côté serveur :

const express = require('express');
const app = express();
const PORT = 3000;

app.get('/events', (req, res) => {
    res.setHeader('Content-Type', 'text/event-stream');
    res.setHeader('Cache-Control', 'no-cache');
    res.setHeader('Connection', 'keep-alive');

    const sendEvent = (data) => {
        res.write(`data: ${JSON.stringify(data)}\n\n`);
    };

    const intervalId = setInterval(() => {
        sendEvent({ message: 'Hello from server', timestamp: new Date() });
    }, 5000);

    req.on('close', () => {
        clearInterval(intervalId);
        res.end();
    });
});

app.listen(PORT, () => {
    console.log(`Server running on http://localhost:${PORT}`);
});

Configuration du Frontend avec React Query

Commencez par installer les dépendances :

npm install @tanstack/react-query

Ensuite, créez un composant React pour consommer les événements côté client :

import React from 'react';
import { useQueryClient, useQuery } from '@tanstack/react-query';

const useEventSource = (url, onEvent) => {
    React.useEffect(() => {
        const eventSource = new EventSource(url);
        eventSource.onmessage = (event) => {
            const data = JSON.parse(event.data);
            onEvent(data);
        };

        return () => {
            eventSource.close();
        };
    }, [url, onEvent]);
};

const EventComponent = () => {
    const queryClient = useQueryClient();
    const eventsUrl = 'http://localhost:3000/events';

    useEventSource(eventsUrl, (data) => {
        queryClient.setQueryData('events', (oldData) => [...(oldData || []), data]);
    });

    const { data: events = [] } = useQuery('events', {
        initialData: []
    });

    return (
        <div>
            <h1>Server-Sent Events</h1>
            <ul>
                {events.map((event, index) => (
                    <li key={index}>{event.message} - {new Date(event.timestamp).toString()}</li>
                ))}
            </ul>
        </div>
    );
};

export default EventComponent;

Intégration de React Query Provider

Assurez-vous que votre App.jsx ou index.jsx ressemble à ceci pour inclure le React Query Provider :

import React from 'react';
import ReactDOM from 'react-dom';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import EventComponent from './EventComponent';

const queryClient = new QueryClient();

ReactDOM.render(
    <QueryClientProvider client={queryClient}>
        <EventComponent />
    </QueryClientProvider>,
    document.getElementById('root')
);

Voilà, vous avez maintenant un système d'EventSource fonctionnant avec Node.js côté backend et React Query côté frontend. Cette configuration vous permet de recevoir des mises à jour en temps réel depuis le serveur, tout en simplifiant significativement la gestion et la mise en œuvre par rapport aux WebSockets.