0Pricing
React Academy · Aula

Criando um componente de chat em tempo real

Exiba mensagens ao vivo em uma lista de chat com rolagem usando eventos WebSocket e o estado do React.

Criando um componente de chat em tempo real é uma aula grátis de React Academy no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de React Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de React Academy inclui 4 aulas no total.

Arquitetura do componente de bate-papo

Um bate-papo em tempo real tem três partes: uma lista de mensagens (exibição), um campo de entrada de mensagens (envio) e a camada de conexão WebSocket/Socket.IO. Mantenha a lógica do socket em um gancho personalizado.

Formato dos dados da mensagem

Defina uma interface do TypeScript para as mensagens do bate-papo, mantendo o componente com segurança de tipos em toda a aplicação.

interface Message {
  id: string;
  text: string;
  sender: string;
  timestamp: number;
}

const [messages, setMessages] = useState<Message[]>([]);

Gancho useChat

Encapsule a conexão, o estado das mensagens e a função de envio em um único gancho.

function useChat(roomId: string) {
  const [messages, setMessages] = useState<Message[]>([]);

  useEffect(() => {
    socket.connect();
    socket.emit('join-room', roomId);
    socket.on('message', (msg: Message) => setMessages(m => [...m, msg]));
    return () => {
      socket.off('message');
      socket.emit('leave-room', roomId);
      socket.disconnect();
    };
  }, [roomId]);

  const sendMessage = useCallback((text: string) => {
    const msg: Message = { id: crypto.randomUUID(), text, sender: 'me', timestamp: Date.now() };
    socket.emit('message', msg);
  }, []);

  return { messages, sendMessage };
}

Componente de lista de mensagens

Renderize as mensagens em uma lista com rolagem. Use useRef no marcador inferior e role até ele quando novas mensagens chegarem.

function MessageList({ messages }: { messages: Message[] }) {
  const bottomRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    bottomRef.current?.scrollIntoView({ behavior: 'smooth' });
  }, [messages]);

  return (
    <div className="message-list">
      {messages.map(msg => (
        <div key={msg.id} className={`msg ${msg.sender === 'me' ? 'mine' : 'theirs'}`}>
          <span>{msg.sender}</span>
          <p>{msg.text}</p>
        </div>
      ))}
      <div ref={bottomRef} />
    </div>
  );
}

Componente de entrada de mensagens

Um campo de entrada controlado que emite ao pressionar Enter ou clicar no botão. Limpe o campo de entrada depois do envio.

function MessageInput({ onSend }: { onSend: (text: string) => void }) {
  const [text, setText] = useState('');

  const handleSend = () => {
    if (!text.trim()) return;
    onSend(text.trim());
    setText('');
  };

  return (
    <div className="input-row">
      <input
        value={text}
        onChange={e => setText(e.target.value)}
        onKeyDown={e => e.key === 'Enter' && handleSend()}
        placeholder="Type a message..."
      />
      <button onClick={handleSend}>Send</button>
    </div>
  );
}

Montando a interface do bate-papo

Combine o gancho e os subcomponentes em um componente ChatRoom.

function ChatRoom({ roomId }: { roomId: string }) {
  const { messages, sendMessage } = useChat(roomId);

  return (
    <div className="chat-room">
      <h2>Room: {roomId}</h2>
      <MessageList messages={messages} />
      <MessageInput onSend={sendMessage} />
    </div>
  );
}

Atualizações otimistas

Adicione a mensagem ao estado local imediatamente, antes que o servidor a confirme, fornecendo um retorno instantâneo. Reconcilie a mensagem ou remova-a se o servidor retornar um erro.

const sendMessage = useCallback((text: string) => {
  const optimistic: Message = { id: crypto.randomUUID(), text, sender: 'me', timestamp: Date.now() };
  setMessages(m => [...m, optimistic]); // instant feedback
  socket.emit('message', optimistic, (err) => {
    if (err) setMessages(m => m.filter(msg => msg.id !== optimistic.id));
  });
}, []);

Indicadores de digitação

Emita um evento de typing quando o campo de entrada mudar (com atraso controlado) e ouça os eventos de digitação de outras pessoas para exibir um indicador.

const emitTyping = useMemo(() => debounce(() => socket.emit('typing'), 300), []);

useEffect(() => {
  socket.on('user-typing', (user) => setTypingUser(user));
  return () => socket.off('user-typing');
}, []);

Marcas de tempo das mensagens

Formate as marcas de tempo com Intl.DateTimeFormat para exibi-las de acordo com a localidade.

function formatTime(ts: number) {
  return new Intl.DateTimeFormat('en', { hour: '2-digit', minute: '2-digit' }).format(ts);
}

<span className="timestamp">{formatTime(msg.timestamp)}</span>

Confirmações de leitura

Emita um evento de read quando o usuário visualizar as mensagens e ouça as confirmações de leitura do servidor para mostrar marcas de verificação.

Lista de mensagens virtualizada

Para históricos longos de bate-papo, use react-window ou react-virtual para virtualizar a lista de mensagens e renderizar apenas as linhas visíveis.

Limitando o histórico de mensagens

Limite a quantidade de mensagens no estado para evitar o crescimento ilimitado do uso de memória em sessões longas.

socket.on('message', (msg: Message) => {
  setMessages(prev => [...prev.slice(-499), msg]); // keep last 500
});

Verificação rápida

Qual é a finalidade de rolar até o elemento div marcador inferior quando novas mensagens chegam a uma lista de bate-papo?

Recapitulação

Crie um bate-papo em tempo real com um gancho useChat que encapsule a lógica do socket, uma MessageList com rolagem automática e uma MessageInput que seja limpa após o envio. Use atualizações otimistas para fornecer retorno instantâneo e limite o histórico de mensagens para evitar vazamentos de memória.

Perguntas Frequentes

A aula “Criando um componente de chat em tempo real” é grátis?

Sim — o texto completo de “Criando um componente de chat em tempo real” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de React Academy, atualize para CoddyKit PRO. O curso de React Academy inclui 4 aulas no total.

O que vou aprender em “Criando um componente de chat em tempo real”?

Exiba mensagens ao vivo em uma lista de chat com rolagem usando eventos WebSocket e o estado do React. Você pratica React Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar React Academy?

Nenhuma experiência prévia é necessária. React Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.

Quanto tempo leva a aula “Criando um componente de chat em tempo real”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de React Academy?

Sim. Cada aula de React Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Fundamentos de WebSocket no navegador
  2. Usando Socket.IO com React
  3. Criando um componente de chat em tempo real
  4. Reconexão, tratamento de erros e limpeza
← Voltar para React Academy