Echtzeitfunktionen – Live-Chat, Benachrichtigungen, gemeinsame Bearbeitung, Live-Dashboards – erfordern eine dauerhafte Verbindung. In ReactSocket.io ist die praktischste Möglichkeit, WebSocket-basierte Echtzeitfunktionen hinzuzufügen. Diese Anleitung zeigt, wie man es sauber mit React-Hooks integriert.
📋 Table of Contents
Einrichtung
npm install socket.io-client
Grundlegende Verbindung
// socket.js - create a single shared socket instance
import { io } from 'socket.io-client';
export const socket = io('http://localhost:3001', {
autoConnect: false, // connect manually when ready
reconnection: true,
reconnectionDelay: 1000,
});
Ein wiederverwendbarer Steckdosenhaken
// hooks/useSocket.js
import { useEffect, useState } from 'react';
import { socket } from '../socket';
export function useSocket() {
const [isConnected, setIsConnected] = useState(socket.connected);
useEffect(() => {
socket.connect();
function onConnect() { setIsConnected(true); }
function onDisconnect() { setIsConnected(false); }
socket.on('connect', onConnect);
socket.on('disconnect', onDisconnect);
// Cleanup - CRITICAL to prevent duplicate listeners
return () => {
socket.off('connect', onConnect);
socket.off('disconnect', onDisconnect);
socket.disconnect();
};
}, []);
return { socket, isConnected };
}
Auf Ereignisse achten
// hooks/useMessages.js - subscribe to a specific event
import { useEffect, useState } from 'react';
import { socket } from '../socket';
export function useMessages() {
const [messages, setMessages] = useState([]);
useEffect(() => {
function onMessage(msg) {
setMessages(prev => [...prev, msg]);
}
socket.on('message', onMessage);
// Always clean up the listener to avoid duplicates on re-render
return () => {
socket.off('message', onMessage);
};
}, []);
const sendMessage = (text) => {
socket.emit('send_message', { text, timestamp: Date.now() });
};
return { messages, sendMessage };
}
Eine vollständige Chat-Komponente
import { useState } from 'react';
import { useSocket } from './hooks/useSocket';
import { useMessages } from './hooks/useMessages';
function Chat() {
const { isConnected } = useSocket();
const { messages, sendMessage } = useMessages();
const [input, setInput] = useState('');
const handleSend = (e) => {
e.preventDefault();
if (input.trim()) {
sendMessage(input);
setInput('');
}
};
return (
<div>
<div>Status: {isConnected ? 'Connected' : 'Disconnected'}</div>
<ul>
{messages.map((msg, i) => (
<li key={i}>{msg.text}</li>
))}
</ul>
<form onSubmit={handleSend}>
<input value={input} onChange={e => setInput(e.target.value)} />
<button type="submit">Send</button>
</form>
</div>
);
}
Tippindikatoren und Präsenz
export function useTyping() {
const [typingUsers, setTypingUsers] = useState([]);
useEffect(() => {
function onTyping({ user, isTyping }) {
setTypingUsers(prev =>
isTyping
? [...new Set([...prev, user])]
: prev.filter(u => u !== user)
);
}
socket.on('user_typing', onTyping);
return () => socket.off('user_typing', onTyping);
}, []);
const setTyping = (isTyping) => {
socket.emit('typing', { isTyping });
};
return { typingUsers, setTyping };
}
Handhabung der Wiederverbindung
useEffect(() => {
function onReconnect() {
console.log('Reconnected - re-syncing state');
// Re-fetch missed data or re-join rooms after reconnection
socket.emit('rejoin_room', { roomId });
}
socket.io.on('reconnect', onReconnect);
return () => socket.io.off('reconnect', onReconnect);
}, [roomId]);
// Socket.io auto-reconnects; use this hook to re-sync after connection drops
Die entscheidende Regel: Hörer immer bereinigen
Der häufigste Socket.io + React-Fehler sind doppelte Event-Handler. Jedes Mal, wenn eine Komponente erneut gerendert oder bereitgestellt wird und Sie einen Listener hinzufügen, ohne den alten zu entfernen, sammeln sich Duplikate an – eine einzelne Nachricht löst Ihren Handler mehrmals aus. Geben Sie immer eine Bereinigungsfunktion von useEffect zurück, die den Listener mitsocket.off()entfernt . Dies ist für korrektes Verhalten nicht verhandelbar.
Authentifizierung
// Pass auth token when connecting
export const socket = io('http://localhost:3001', {
auth: {
token: localStorage.getItem('accessToken'),
},
autoConnect: false,
});
// Server verifies the token in a middleware before allowing the connection
// Update the token if it changes:
socket.auth.token = newToken;
socket.disconnect().connect(); // reconnect with new auth
Häufig gestellte Fragen
F: Warum erhalte ich doppelte Nachrichten?
A: Sie fügen Ereignis-Listener hinzu, ohne sie zu bereinigen. Bei jedem erneuten Rendern wird ein weiterer Listener hinzugefügt. Geben Sie immer eine Bereinigungsfunktion von useEffect zurück, diesocket.off()aufruft um den Listener zu entfernen. Dies ist der häufigste Socket.io + React-Fehler.
F: Soll ich den Socket innerhalb oder außerhalb der Komponente erstellen?
A: Außerhalb – erstellen Sie eine einzelne gemeinsam genutzte Socket-Instanz in einem separaten Modul (socket.js) und importieren Sie sie. Wenn Sie es innerhalb einer Komponente erstellen, entsteht bei jedem Rendern eine neue Verbindung. Eine gemeinsame Instanz ist das richtige Muster.
F: Wie gehe ich mit dem Socket in mehreren Komponenten um?
A: Importieren Sie die Shared-Socket-Instanz in jede Komponente, die sie benötigt, oder verwenden Sie einen Kontextanbieter, um den Verbindungsstatus freizugeben. Jede Komponente abonniert die Ereignisse, die sie benötigt (mit Bereinigung), über ihren eigenen useEffect. Der einzelne Socket verarbeitet sie alle.
F: Socket.io oder natives WebSocket?
A: Socket.io für Produktions-React-Apps – es fügt automatische Wiederverbindung, Fallback auf Long-Polling, Räume und eine ereignisbasierte API hinzu, die viel Arbeit spart. Native WebSocket ist eine niedrigere Ebene und erfordert, dass Sie die Wiederverbindung und die Ereignisbehandlung selbst erstellen.
F: Wie teste ich Echtzeitfunktionen?
A: Öffnen Sie die App in mehreren Browser-Registerkarten oder -Fenstern, um mehrere Benutzer zu simulieren und die Verbreitung von Nachrichten/Ereignissen zu überprüfen. Für automatisierte Tests simulieren Sie den Socket oder verwenden Sie einen Test-Socket.io-Server. Manuelle Multi-Tab-Tests sind der schnellste Weg, um zu überprüfen, ob das Verhalten in Echtzeit funktioniert.
Fazit
Das Hinzufügen von Echtzeitfunktionen zu React mit Socket.io ist mit den richtigen Mustern unkompliziert:Erstellen Sie eine einzelne gemeinsam genutzte Socket-Instanz außerhalb von Komponenten, wickeln Sie die Verbindung und die Ereignisbehandlung in benutzerdefinierte Hooks ein und bereinigen Sie IMMER Listener in der Rückgabefunktion von useEffect. Das benutzerdefinierte Hook-Muster (useSocket, useMessages, useTyping) sorgt dafür, dass Ihre Echtzeitlogik organisiert und wiederverwendbar bleibt. Bewältigen Sie die erneute Verbindung, indem Sie den Status nach der Wiederherstellung der Verbindung erneut synchronisieren, und übergeben Sie Authentifizierungstoken bei der Verbindung für gesicherte Sockets. Die wichtigste Regel besteht darin, die Listener mitsocket.off()zu bereinigen – Das Vergessen führt zu doppelten Handlern und ist der häufigste Socket.io + React-Fehler. Mit diesen Mustern können Sie Chats, Benachrichtigungen, Live-Dashboards und Funktionen für die Zusammenarbeit sauber in React erstellen.
🔗 Share this article
✍️ Leave a Comment