Communitygithub.com

jaimegago/agent-skills

Use durante a depuração quando uma interface React não reflete dados sabidamente corretos em sua origem — um componente renderiza nada ou conteúdo desatualizado mesmo que a API retorne a resposta correta, um hook react-query / de busca de dados parece travado, ou o painel de rede mostra um 200 bem-sucedido mas a interface nunca atualiza. Para DIAGNOSTICAR esse comportamento de tempo de execução/timing inspecionando o estado ativo do componente, diferente de construir ou estilizar a interface. Não serve para erros de build/compilação, problemas exclusivamente de estilo, ou casos onde a API genuinamente retorna dados errados ou ausentes.

O que é agent-skills?

Esta skill auxilia desenvolvedores a diagnosticarem bugs de tempo de execução em aplicações React onde os dados chegam corretamente da API mas a interface do usuário (UI) não reflete esses dados. O problema geralmente está em interações de runtime/timing entre componentes, e não em arquivos de código-fonte individuais. A skill oferece uma abordagem estruturada para inspecionar o estado ativo do componente — especialmente observadores de consulta do react-query — em vez de reler o código-fonte. Ela é suportada em projetos que usam @tanstack/react-query v5.90+ e React 18, fornecendo snippets de console para caminhar pela árvore de fibras do React e inspecionar hooks. A skill também inclui um diagrama de decisão para diferenciar entre "caminho de dados quebrado" e "consulta abandonada no meio do voo" (stranded mid-flight), orientando o desenvolvedor a identificar a causa raiz, como ações de ciclo de vida ou gerenciamento de cache.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/jaimegago/agent-skills/tree/HEAD/frontend-runtime-debugging

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Depuração de Frontend em Tempo de Execução: inspecione o estado ativo antes de reler o código-fonte

Os dados estão corretos na rede mas a interface está errada. Isto é um bug de runtime/timing, e o instinto que fará você perder tempo é reler os arquivos-fonte. Resista a ele. Reordene o reflexo.

Quando usar

Invoke durante a depuração, quando o sintoma aparecer — não no início da tarefa. Use quando TODAS estas condições se aplicarem:

  • Um componente React renderiza conteúdo vazio, desatualizado ou nenhum conteúdo.
  • Os dados que ele precisa são sabidamente corretos na origem (a API/backend retorna a resposta certa).
  • A lacuna está em algum lugar entre "resposta correta na rede" e "renderização correta na tela".

Frases típicas: "a API retorna os dados certos mas o componente está em branco", "react-query está travado", "a requisição é 200 mas a UI nunca atualiza", "funciona após um refresh mas não no primeiro carregamento".

Para o que NÃO serve

  • Erros de build / compilação — isso é um bug de toolchain, não de runtime.
  • Problemas exclusivamente de estilo / layout — os dados renderizam, só estão com aparência errada.
  • A API genuinamente retorna dados errados ou nenhum dado — isso é um bug normal de backend/contrato. Verifique a resposta na rede PRIMEIRO; se a resposta estiver realmente errada ou vazia, pare e corrija o backend/contrato. Esta skill é apenas para quando a rede está correta mas a UI não está.

A reordenação (a lição fundamental)

  1. Inspecione o estado de runtime ativo ANTES de reler o código-fonte. O reflexo é reler o componente, schema, layout e a fiação do provedor procurando o bug. Quando os dados estão corretos na rede mas a UI não está, esse reflexo é uma armadilha: o bug frequentemente NÃO está em um único arquivo-fonte, mas em uma interação de runtime/timing entre peças que são, individualmente, corretas. A revisão de código-fonte é estruturalmente cega a essa classe de bugs. Olhe para o estado ativo primeiro.

  2. Um 200 no painel de rede pode enganar ativamente. Uma requisição mostrando 200 significa que a resposta chegou. Isso NÃO significa que os dados alcançaram o componente ou foram commitados no cache. A resposta pode chegar e ser descartada, removida ou nunca commitada. Não conclua "a busca funciona" a partir de um 200 — confirme que os dados realmente alcançaram o estado do componente consumidor.

  3. Para react-query, inspecione o observador de consulta ativo do componente afetado, não apenas a rede. Leia os campos status, fetchStatus, dataUpdateCount e error do observador.

    • Uma consulta travada em status: "pending" / fetchStatus: "fetching" com dataUpdateCount: 0 significa que o resultado da promise da queryFn nunca foi commitado no observador. Isso aponta para a consulta ter sido removida ou invalidada durante o voo — NÃO para uma falha na busca.
    • Confirme que a própria queryFn está saudável forçando o observador a refazer a busca. Se uma refetch manual resolver corretamente e imediatamente, a busca/cliente/schema estão todos bem, e o verdadeiro bug é que a consulta inicial foi abandonada (removida por uma purga de cache, invalidada por um efeito, ou derrubada por um remount). Esta única observação distingue "o caminho de dados está quebrado" de "o caminho de dados está bem mas a consulta foi morta" — bugs completamente diferentes.
  4. Uma vez localizado como "consulta abandonada durante o voo", procure upstream no gerenciamento de ciclo de vida/cache. A causa é algo que foi executado no mesmo momento em que a consulta começou: um removeQueries / invalidateQueries / reset de cache, ou uma corrida de mount/unmount/remount. Olhe para efeitos de transição de autenticação/sessão, purgas de troca de principal/tenant e remounts de provedor — NÃO para o código de busca.

Caminho de decisão

UI errada, dados corretos na origem?
  → confirme que a resposta na rede está realmente correta (não é trabalho desta skill se não estiver)
  → leia o observador de consulta ativo do componente afetado
       status pending + fetchStatus fetching + dataUpdateCount 0?
          → force uma refetch naquele observador
               refetch resolve instantaneamente e corretamente?
                  → queryFn está OK. Bug = consulta inicial abandonada.
                    Caça upstream: removeQueries/invalidateQueries/reset,
                    corrida de remount/unmount, efeito de purga de auth/sessão/tenant.
               refetch também falha?
                  → caminho de dados genuinamente quebrado. Inspecione queryFn/cliente/schema.
       tem dados mas UI ainda em branco?
          → bug de render/seletor/condicional no componente, agora releia o código-fonte.

Ferramentas de inspeção ao vivo (pistas, não APIs estáveis)

Estes snippets alcançam o observador react-query de um componente a partir de uma página em execução, caminhando pela árvore de fibras do React a partir de um elemento DOM renderizado, leem o estado atual da consulta do observador e forçam uma refetch para provar que a queryFn funciona.

Estes snippets são sensíveis à versão. Eles foram derivados contra @tanstack/react-query v5.90 e internals de fibras do React 18, dependem de internals não documentados e IRÃO se desatualizar. Trate-os como pontos de partida para adaptar — reverifique os nomes dos campos e a forma das fibras contra as versões instaladas do projeto antes de confiar em qualquer resultado. Eles são pistas, não APIs garantidamente estáveis.

Caminhe pela árvore de fibras a partir de um nó DOM para encontrar hooks/observadores:

// Escolha um elemento DOM renderizado pelo componente afetado (ex: via $0 nas devtools).
const el = $0; // ou document.querySelector('[data-testid="..."]')
const key = Object.keys(el).find(k => k.startsWith('__reactFiber$'));
let fiber = el[key];

// Caminhe para cima/baixo na árvore de fibras; memoizedState é uma lista ligada de hooks.
// react-query armazena seu observador no memoizedState de um hook.
function* fibers(root) {
  const stack = [root];
  while (stack.length) {
    const f = stack.pop();
    if (!f) continue;
    yield f;
    if (f.child) stack.push(f.child);
    if (f.sibling) stack.push(f.sibling);
  }
}

// Escaneie o estado do hook por algo que pareça um QueryObserver.
function findObservers(fiber) {
  const found = [];
  for (const f of fibers(fiber)) {
    let hook = f.memoizedState;
    while (hook) {
      const s = hook.memoizedState;
      if (s && typeof s === 'object') {
        // Instâncias de QueryObserver expõem getCurrentResult()/getCurrentQuery().
        if (typeof s.getCurrentResult === 'function') found.push(s);
        // Algumas versões aninham; verifique também wrappers comuns.
        if (s.observer && typeof s.observer.getCurrentResult === 'function') found.push(s.observer);
      }
      hook = hook.next;
    }
  }
  return found;
}

const observers = findObservers(fiber);

Leia o estado da consulta ativa de um observador:

const obs = observers[0];
const r = obs.getCurrentResult();
console.log({
  status: r.status,            // 'pending' | 'error' | 'success'
  fetchStatus: r.fetchStatus,  // 'fetching' | 'paused' | 'idle'
  dataUpdateCount: obs.getCurrentQuery().state.dataUpdateCount,
  error: r.error,
});
// pending + fetching + dataUpdateCount 0  ==>  abandonada durante o voo, não uma falha na busca.

Force uma refetch para provar que a queryFn está saudável:

obs.refetch().then(r => console.log('refetch:', r.status, r.data)).catch(e => console.log('refetch falhou:', e));
// Resolve instantaneamente e corretamente  ==>  queryFn/cliente/schema estão bons;
//                                               a consulta original foi morta upstream.

Se o projeto expuser o QueryClient (ex: no window para depuração, ou acessível a partir de uma fibra de provedor), prefira queryClient.getQueryCache().findAll() e inspecione o state e observers de cada consulta diretamente — é mais robusto do que caminhar por fibras, quando disponível.

Conclusão

Quando você tiver localizado o bug:

  1. Declare em qual lado da bifurcação ele caiu: "caminho de dados quebrado" vs "consulta abandonada".
  2. Se abandonada, nomeie a ação de ciclo de vida/cache upstream que a matou.
  3. Só então releia o arquivo-fonte específico responsável — agora você sabe qual é.

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

Habilidades Relacionadas