How to Manage Message History in a Chat with React



This content originally appeared on DEV Community and was authored by Werliton Silva

IndexedDB, WebSocket e React Query trabalhando juntos para um chat moderno, performático e fluido.

Construir um chat moderno e fluido exige mais do que apenas um backend em tempo real. O desafio é entregar velocidade, resiliência offline e sincronização precisa do histórico de mensagens.

Neste artigo, compartilho uma abordagem eficiente usando:

  • React + WebSocket para mensagens em tempo real
  • IndexedDB para persistir o histórico no client
  • React Query para gestão e sincronização do estado

✨ Cenário

Chat

Imagine um app de chat onde:

  • Ao abrir a conversa, o usuário já vê o histórico instantaneamente
  • Mensagens novas aparecem em tempo real
  • É possível rolar para carregar mensagens antigas
  • Mesmo offline, é possível ver mensagens anteriores

Vamos montar esse fluxo!

📂 1. Armazenamento local com IndexedDB (via Dexie.js)

pnpm add dexie
// db.ts
import Dexie from 'dexie';

export const chatDB = new Dexie('chatDB');
chatDB.version(1).stores({
  messages: '++id, chatId, timestamp'
});

🚀 2. Carregamento inicial com cache local

const loadCachedMessages = async (chatId: string) => {
  return await chatDB.table('messages')
    .where('chatId')
    .equals(chatId)
    .sortBy('timestamp');
};

Ao abrir o chat, exiba essas mensagens imediatamente antes de sincronizar com o servidor.

🔄 3. Sincronização com backend (React Query)

import { useQuery } from '@tanstack/react-query';

const fetchLatestMessages = async (chatId: string, after: number) => {
  const res = await fetch(`/api/messages?chatId=${chatId}&after=${after}`);
  return res.json();
};

const { data: newMessages } = useQuery({
  queryKey: ['messages', chatId],
  queryFn: () => fetchLatestMessages(chatId, lastLocalTimestamp),
});

E salve essas mensagens também no IndexedDB:

chatDB.table('messages').bulkPut(newMessages);

🔌 4. WebSocket para mensagens em tempo real

const socket = new WebSocket('wss://meuapp.com/ws');

socket.onmessage = (event) => {
  const message = JSON.parse(event.data);
  updateUI(message);
  chatDB.table('messages').add(message);
};

⬆ 5. Scroll infinito para mensagens antigas

Use paginação com timestamp < para buscar blocos anteriores do histórico, e combine com cache local.

🚀 Conclusão

Com IndexedDB + React Query + WebSocket:

  • O usuário vê mensagens mesmo offline
  • O app é responsivo e parece “instantâneo”
  • As mensagens estão sempre sincronizadas

Se você quer entregar uma experiência de chat digna de app nativo, esse é o caminho.

Quer o repositório de exemplo ou ver esse fluxo em funcionamento? Comenta aqui ou me chama no LinkedIn!


This content originally appeared on DEV Community and was authored by Werliton Silva