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ério | Exemplo |
|---|---|---|
| 1 | Listagem de dados — endpoint retorna array de itens | Escolas, alunos, turmas, olimpíadas, faturas |
| 2 | Dados compartilhados — mais de 1 componente consome o mesmo dado | Permissões do usuário, métricas de dashboard |
| 3 | Dados com paginação ou filtros — queryKey deve variar por parâmetro | Logs, SMS logs, faturas com filtro de status |
| 4 | Tela de dashboard/painel — carrega métricas ou resumos | Dashboard coordenador, dashboard escola |
| 5 | Dados que crescem — volume tende a aumentar com o uso | Alunos, inscrições, resultados, publicações |
| 6 | CRUD completo — tela com create + update + delete | Tarefas, 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
| Categoria | staleTime | gcTime | Exemplo |
|---|---|---|---|
| Dados quase estáticos | 30min | 60min | Anos de participação, séries |
| Configurações | 10min | 30min | Permissões, portal config |
| Dados operacionais | 5min | 30min | Escolas, alunos, turmas |
| Dashboards | 5min | 15min | Métricas, estatísticas |
| Dados em tempo real | 1min | 5min | Notificações, presença |
| Dados com refresh manual | 5min | 30min | Logs (usuário força refresh) |
3. Template de Cache Keys
// 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
const CACHE_CONFIG = {
staleTime: 5 * 60 * 1000, // 5 min
gcTime: 30 * 60 * 1000, // 30 min
refetchOnWindowFocus: false,
};5. Regras de Invalidação
onSuccessde toda mutation:queryClient.invalidateQueries({ queryKey: QUERY_KEYS.all })- Cross-módulo: invalidar queries relacionadas (ex: criar escola invalida
['admin-dashboard']) - Nunca
setQueryDatamanual para listas — preferirinvalidateQueriespara garantir consistência
6. Checklist de Análise (para planejamento)
Ao planejar um novo hook, responder:
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órioSe 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:
// ❌ 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();
}, []);// ✅ 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ênciasrc/hooks/useGestaoResultados.ts— Exemplo comgetUserFriendlyError+ sanitização completasrc/hooks/useBannersLogin.ts— Exemplo de migração de cache manual → React Query