Construisons un chat en temps réel avec WebSocket, React et Node.js

Chaque jour, nous interagissons avec des apps qui réagissent instantanément : WhatsApp, Slack, Figma, Notion… Derrière cette fluidité magique se cache une technologie puissante : WebSocket.

Dans ce tutoriel, on décortique le fonctionnement du temps réel sur le web, puis on code ensemble une application de chat minimaliste avec React, TypeScript et Node.js.

1. Protocoles de communication : du classique au temps réel

Avant de plonger dans WebSocket, comprenons d'abord comment un navigateur parle à un serveur — et pourquoi HTTP seul ne suffit pas pour le temps réel.

1.1 HTTP Polling:

Le client interroge régulièrement le serveur : « Y a-t-il du nouveau ? »

  • ✅ Simple à implémenter
  • ✅ Universellement compatible
  • ❌ Inefficace : requêtes répétées, souvent vides
  • ❌ Latence élevée sur les connexions lentes

1.2. Long Polling:

Le client envoie une requête… et le serveur la retient jusqu'à avoir une réponse. Dès qu'il répond, le client relance une nouvelle requête.

  • ✅ Moins de requêtes inutiles
  • ✅ Quasi temps réel sans WebSocket
  • ❌ Toujours basé sur HTTP
  • ❌ Complexité accrue côté serveur (gestion des connexions ouvertes)

1.3. Server-Sent Events (SSE):

Le serveur pousse des données au client via une connexion HTTP unidirectionnelle (EventSource en JS).

  • ✅ Parfait pour les flux serveur → client (notifications, logs, dashboards)
  • ✅ Léger et natif
  • ❌ Unidirectionnel : impossible d'envoyer du client au serveur
  • ❌ Texte uniquement (pas de binaire)

1.4. WebSocket:

Une connexion persistante, bidirectionnelle et full-duplex entre client et serveur. Plus besoin de requêtes HTTP : les deux parties échangent librement, en temps réel.

  • ✅ Temps réel natif
  • ✅ Faible latence, faible overhead
  • ✅ Échanges bidirectionnels (idéal pour le chat !)
  • ❌ Nécessite un serveur compatible
  • ❌ Sécurité et déboggage plus complexes

Prêt à coder ? Dans la suite, on met en pratique tout ça en construisant notre propre chat temps réel !

2. Application

Mise en place du serveur WebSocket (Node.js):

2.1. Crée un nouveau dossier "server" à partir du terminal

mkdir server cd server npm init -y npm install ws

2.2. Crée ensuite un fichier server.js :

import { WebSocketServer } from 'ws';

const PORT = 7500
const wss = new WebSocketServer({ port: PORT });
console.log(`Le serveur WebSocket est en cours d'exécution sur ws://localhost:${PORT}`);

wss.on('connection', (ws) => {
  console.log('Nouveau client connecté');

  ws.on('message', (message) => {
    console.log(`message reçu: ${message.toString()}`);

    // Diffuser le message à tous les clients
    wss.clients.forEach((client) => {
            if (client.readyState === ws.OPEN) {
              client.send(message.toString());
            }
    });
  });
  ws.on('close', () => {
    console.log('Client déconnecté');
  })

})

2.3. Lance ton serveur avec

node server.js

2.4. Création du projet React avec Vite: ouvre un nouveau terminal

Crée un projet React + TypeScript avec Vite

npm create vite@latest client -- --template react-ts

Entre dans le dossier

cd client

Tu peux maintenant lancer le serveur de développement :

npm run dev

Ouvre ton navigateur à l'adresse: http://localhost:5173 pour voir ton application React.

2.5. React + WebSocket:

Ouvre src/App.tsx et remplace le contenu par :

import React from 'react';

function App() {
	const [socket, setSocket] = React.useState<WebSocket | null>(null);
	const [messages, setMessages] = React.useState<string[]>([]);
	const [inputValue, setInputValue] = React.useState<string>('');

	React.useEffect(() => {
		const ws = new WebSocket('ws://localhost:7500');
		setSocket(ws);

		ws.onmessage = (event) => {
			console.log(event.data);
			setMessages((pre) => [...pre, event.data]);
		};
		return () => {
			ws.close();
		};
	}, []);
	const sendMessage = () => {
		if (socket && inputValue.trim() !== '') {
			socket.send(inputValue.trim());
			setInputValue('');
		}
	};
	return (
		<section className="chat-container">
			<ul className="messages">
				{messages.map((message, index) => (
					<li key={index}>{message}</li>
				))}
			</ul>
			<div className="input-area">
				<input
					type="text"
					value={inputValue}
					onChange={(e) => setInputValue(e.target.value)}
					onKeyDown={(e) => e.key === 'Enter' && sendMessage()}
					placeholder="Tapez un message..."
				/>
				<button onClick={sendMessage}>Envoyer</button>
			</div>
		</section>
	);
}

export default App;

2.6. Un peu de style: Mettre à jour le fichier src/index.css :

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

.chat-container {
  max-width: 400px;
  margin: 50px auto;
  background: #f2f2f2;
  border-radius: 10px;
  padding: 20px;
  font-family: sans-serif;
  box-shadow: 0 4px 10px rgba(0,0,0,0.1);
}

.messages {
  height: 300px;
  overflow-y: auto;
  border: 1px solid #ddd;
  border-radius: 6px;
  padding: 30px;
  background: #fff;
}

.message {
  background: #e0f7fa;
  padding: 8px 12px;
  border-radius: 6px;
  margin-bottom: 6px;
}

.input-area {
  display: flex;
  margin-top: 10px;
}

input {
  flex: 1;
  padding: 8px;
  border: 1px solid #ccc;
  border-radius: 6px;
}

button {
  margin-left: 8px;
  padding: 8px 14px;
  background: #0077ff;
  color: white;
  border: none;
  border-radius: 6px;
  cursor: pointer;
}

button:hover {
  background: #005bcc;
}

3. Test final

  1. Démarre ton serveur WebSocket :
    node server/server.js
  2. Lance ton app React sur un autre terminal (tab) :
    npm run dev
  3. Ouvre deux onglets du navigateur sur http://localhost:5173.
  4. Tape un message dans l'un : il apparaît instantanément dans les deux 🎉

4. Ce qu'on a appris

  • Les différences entre "HTTP Polling", "SSE", et "WebSocket"
  • Comment mettre en place un "serveur WebSocket Node.js"
  • Comment connecter un "client React" à ce serveur
  • Comment envoyer/recevoir des messages en "temps réel"

Code final : https://github.com/BrahimS/chat-app-ws-react