🌐 Detecting your location…

Como usar WebSockets no React com Socket.io em 2026: guia completo

⏱️5 min read  ·  1,022 words

Recursos em tempo real — chat ao vivo, notificações, edição colaborativa, painéis ao vivo — exigem uma conexão persistente. Em Reagir,Soquete.io é a maneira mais prática de adicionar funcionalidade em tempo real baseada em WebSocket. Este guia mostra como integrá-lo de forma limpa com ganchos React.

Configuração

npm install socket.io-client

Conexão Básica

// 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,
});

Um gancho useSocket reutilizável

// 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 };
}

Ouvindo Eventos

// 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 };
}

Um componente completo de bate-papo

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>
  );
}

Indicadores de digitação e presença

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 };
}

Lidando com a reconexão

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

A regra crítica: sempre limpe os ouvintes

O bug mais comum do Socket.io + React são manipuladores de eventos duplicados. Cada vez que um componente é renderizado ou remontado, se você adicionar um ouvinte sem remover o antigo, você acumula duplicatas – uma única mensagem aciona seu manipulador várias vezes. Sempre retorne uma função de limpeza de useEffect que remove o ouvinte comsocket.off(). Isso não é negociável para o comportamento correto.

Autenticação

// 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

Perguntas Frequentes

P: Por que estou recebendo mensagens duplicadas?
R: Você está adicionando ouvintes de eventos sem limpá-los. Cada nova renderização adiciona outro ouvinte. Sempre retorne uma função de limpeza de useEffect que chamasocket.off() para remover o ouvinte. Este é o erro mais comum do Socket.io + React.

P: Devo criar o soquete dentro ou fora do componente?
R: Fora — crie uma única instância de soquete compartilhado em um módulo separado (socket.js) e importe-o. Criá-lo dentro de um componente causa uma nova conexão em cada renderização. Uma instância compartilhada é o padrão correto.

P: Como faço para lidar com o soquete em vários componentes?
R: Importe a instância de soquete compartilhado em cada componente que precisa dele ou use um provedor de contexto para compartilhar o estado da conexão. Cada componente assina os eventos necessários (com limpeza) por meio de seu próprio useEffect. O único soquete lida com todos eles.

P: Socket.io ou WebSocket nativo?
R: Socket.io para aplicativos React de produção – adiciona reconexão automática, fallback para pesquisas longas, salas e uma API baseada em eventos que economiza um trabalho significativo. O WebSocket nativo é de nível inferior e exige que você mesmo crie a reconexão e o tratamento de eventos.

P: Como posso testar recursos em tempo real?
R: Abra o aplicativo em várias guias ou janelas do navegador para simular vários usuários e verificar a propagação de mensagens/eventos. Para testes automatizados, simule o soquete ou use um servidor Socket.io de teste. O teste manual de múltiplas guias é a maneira mais rápida de verificar se o comportamento em tempo real funciona.

Conclusão

Adicionar recursos em tempo real ao React com Socket.io é simples com os padrões certos:crie uma única instância de soquete compartilhado fora dos componentes, envolva a conexão e a manipulação de eventos em ganchos personalizados e SEMPRE limpe os ouvintes na função de retorno de useEffect. O padrão de gancho personalizado (useSocket, useMessages, useTyping) mantém sua lógica em tempo real organizada e reutilizável. Lide com a reconexão sincronizando novamente o estado após a recuperação da conexão e transmita tokens de autenticação na conexão para soquetes seguros. A regra mais importante é limpar os ouvintes comsocket.off() – esquecer que causa manipuladores duplicados e é o principal bug do Socket.io + React. Com esses padrões, você pode criar chat, notificações, painéis ao vivo e recursos colaborativos de forma limpa no React.

MD Rafikul Islam

Written by

MD Rafikul Islam is a software developer and the editor of TechPulse. He writes about developer tooling, hardware, and the practical decisions that come up in day-to-day engineering work — which laptop to buy, which framework to commit to, why a build broke at 2am. He tests the tools he writes about and says plainly when something is not worth the money. Corrections and corrections requests are welcome at rony.yf25@gmail.com.

✍️ Leave a Comment

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

🌐 Read in:🇬🇧 English🇩🇪 Deutsch🇧🇷 Português🇸🇦 العربية🇮🇳 हिन्दी🇧🇩 বাংলা