Skip to content

React Query — Padrão de Cache Obrigatório

Critérios de decisão, configuração de cache e template para hooks com TanStack React Query.


1. Critérios de Obrigatoriedade

Um hook DEVE usar useQuery/useMutation do TanStack React Query (em vez de useState + useEffect manual) quando qualquer dos critérios abaixo for verdadeiro:

#CritérioExemplo
1Listagem de dados — endpoint retorna array de itensEscolas, alunos, turmas, olimpíadas, faturas
2Dados compartilhados — mais de 1 componente consome o mesmo dadoPermissões do usuário, métricas de dashboard
3Dados com paginação ou filtros — queryKey deve variar por parâmetroLogs, SMS logs, faturas com filtro de status
4Tela de dashboard/painel — carrega métricas ou resumosDashboard coordenador, dashboard escola
5Dados que crescem — volume tende a aumentar com o usoAlunos, inscrições, resultados, publicações
6CRUD completo — tela com create + update + deleteTarefas, usuários, turmas

Exceções válidas para useState manual

  • Estado de formulário/wizard (ex: useImportacaoSessao)
  • Estado efêmero de UI (modais, tabs, seletores)
  • Portal público sem autenticação (ex: usePortalEscola — sessão cookie-based, sem queryKey estável)

2. Tabela de staleTime por Categoria

CategoriastaleTimegcTimeExemplo
Dados quase estáticos30min60minAnos de participação, séries
Configurações10min30minPermissões, portal config
Dados operacionais5min30minEscolas, alunos, turmas
Dashboards5min15minMétricas, estatísticas
Dados em tempo real1min5minNotificações, presença
Dados com refresh manual5min30minLogs (usuário força refresh)

3. Template de Cache Keys

typescript
// Padrão: ['modulo'] ou ['modulo', ...filtros]
const QUERY_KEYS = {
  all:    ['meu-modulo'] as const,
  list:   (filtros: Filtros) => ['meu-modulo', filtros] as const,
  detail: (id: string) => ['meu-modulo', id] as const,
};

4. Configuração Padrão

typescript
const CACHE_CONFIG = {
  staleTime: 5 * 60 * 1000,      // 5 min
  gcTime: 30 * 60 * 1000,        // 30 min
  refetchOnWindowFocus: false,
};

5. Regras de Invalidação

  • onSuccess de toda mutation: queryClient.invalidateQueries({ queryKey: QUERY_KEYS.all })
  • Cross-módulo: invalidar queries relacionadas (ex: criar escola invalida ['admin-dashboard'])
  • Nunca setQueryData manual para listas — preferir invalidateQueries para garantir consistência

6. Checklist de Análise (para planejamento)

Ao planejar um novo hook, responder:

text
1. O endpoint retorna array ou objeto único?
   → Array = useQuery obrigatório
2. Mais de 1 componente vai consumir esse dado?
   → Sim = useQuery obrigatório
3. A tela tem filtros, paginação ou busca?
   → Sim = useQuery com queryKey dinâmico
4. A tela tem operações de escrita (CRUD)?
   → Sim = useMutation + invalidateQueries
5. O volume de dados pode crescer?
   → Sim = useQuery obrigatório

Se qualquer resposta acima indicar useQuery, o hook DEVE usar React Query.


7. Anti-padrão: Legado

Hooks com o padrão abaixo são considerados legado e devem ser migrados:

typescript
// ❌ LEGADO — não usar em código novo
const [items, setItems] = useState<Item[]>([]);
const [loading, setLoading] = useState(false);

useEffect(() => {
  async function load() {
    setLoading(true);
    const res = await invokeAction('funcao', 'list', {});
    if (res.success) setItems(res.data);
    setLoading(false);
  }
  load();
}, []);
typescript
// ✅ CORRETO — usar useQuery
const { data: items = [], isLoading } = useQuery({
  queryKey: ['meu-modulo'],
  queryFn: async () => {
    const res = await invokeAction('funcao', 'list', {});
    if (!res.success) throw new Error(res.message);
    return res.data || [];
  },
  staleTime: 5 * 60 * 1000,
  refetchOnWindowFocus: false,
});

8. Hooks Legados Pendentes de Migração

Todos os hooks identificados como legados foram migrados. Não há pendências.

Hooks já migrados (referência): useAdminEscolas, useBannersLogin, useEventosCalendario, useTarefasEscola, useGestaoResultados, useImportacaoResultados, useMuralEscola, useHeadersNovidades, useCursosData, useTutoriaisData, useTemplatesData, useOlimpiadasData, useOlimpiadasCoordenador, useInscricoesOlimpiada, useVideosCoord, useComunicacaoEscola, useAdminDashboardMetrics, useAdminUsuariosEscola, useEscolaDados, useAnoLetivo, useTransferenciaAlunos, useEscolaPagamentos, useMuralConfig, useGestaoTurmas, useGestaoAlunos, useGestaoResponsaveis, useAdminLogs, useAdminUsuarios, useUserProfile, useTrialInfo, useNotificacoes, useAdminSmsLogs, useAdminAssinaturas, useAdminFaturas, useMercadoPago, useUsuariosEscola, useAdminCronMonitor


Referências

  • NEW_HOOK.md — Template completo de hook com React Query
  • src/hooks/useAdminEscolas.ts — Exemplo de referência
  • src/hooks/useGestaoResultados.ts — Exemplo com getUserFriendlyError + sanitização completa
  • src/hooks/useBannersLogin.ts — Exemplo de migração de cache manual → React Query