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
- Fundamentos de WebSocket no navegador
- Usando Socket.IO com React
- Criando um componente de chat em tempo real
- Reconexão, tratamento de erros e limpeza