O que é spa sindrome do pensamento acelerado e por que ele aparece no seu código
SPA sindrome do pensamento acelerado é o nome que eu uso desde 2019 para descrever um problema recorrente em aplicações Single Page em que o estado da interface se torna tão dinâmico e reativo que cada interação gera uma cascata de re-renderizações que parecem acelerar o pensamento do desenvolvedor, mas na verdade só aumentam bugs de estado e latência percebida pelo usuário. O problema começa normalmente quando você constrói um dashboard com muitos componentes filhos reagindo a eventos globais simultâneos. O state vaza, os useEffects disparam fora da ordem e o componente principal re-renderiza a cada keystroke porque alguém colocou o state de busca no mesmo nível que o state da lista de resultados.
No começo eu achava que era só performance. Depois de passar 47 horas refatorando um sistema de relatórios que travava em qualquer filtro combinado, percebi que não era performance pura. Era arquitetura de estado mal distribuída dentro do modelo de SPA.
spa sindrome do pensamento acelerado na prática
Eu já vi isso em três tipos principais de projeto: sistemas financeiros com atualizações em tempo real via WebSocket, portais de e-commerce com carrinhos e catálogos compartilhados, e ferramentas de BI embeddadas em dashboards internos. Todos tinham o mesmo padrão de colapso sob carga moderada de interações simultâneas. O mecanismo é simples mas traiçoeiro. Quando múltiplos observáveis mudam quase ao mesmo tempo em um componente React ou Vue, o framework faz batch das atualizações, mas se você tem estado derivado calculado inline dentro do render, cada mudança gera um novo cálculo antes que o batch termine. O usuário vê o layout piscar, os números mudarem duas vezes, e o scroll position ser perdido. Tudo em milissegundos, mas perceptível.
Um detalhe que poucos mencionam: o problema piora quando você usa setState dentro de handlers que já estão dentro de efeitos. O efeito dispara, modifica o estado, o estado gatilha o efeito de novo, e o batch do framework nem sempre consegue organizar essa ordem porque o timer do efeito já venceu. Resultado: ciclos infinitos de atualização que parecem resolver sozinhos mas deixam o estado em inconsistência silenciosa. A workaround que funcionou no meu caso foi dividir o estado em três camadas estritas: estado de entrada (o que o usuário digita), estado derivado (o que o sistema calcula a partir da entrada), e estado de UI (coisas como qual aba está abrida, posição de scroll, modais abertos). Cada camada usa um mecanismo diferente. Entrada com controlled components puros. Derivado com selectors memoizados ou computed properties. UI com contexto separado ou store isolada.
O ganho prático foi reduzir de 12 a 3 re-renderizações por interação nos componentes críticos, e eliminar completamente o bug de lista que duplicava itens quando dois filtros eram aplicados em sequência rápida. Antes eu gastava cerca de 6 horas por semana caçando bugs de estado. Depois da separação, caiu para algo em torno de 45 minutos por mês, e metade disso era review preventivo.
👉 Clique no botão abaixo para saber mais sobre o assunto!
Como identificar se seu projeto já está sofrendo
Existem sinais claros. O mais imediato é o profiling de renderização. Se você abrir o React DevTools e clicar em Highlight updates quando estiver testando uma interação simples de filtro ou busca, e ver que mais de cinco componentes diferentes estão piscando ao mesmo tempo, o estado está mal distribuído. Em projetos Vue, o DevTools mostra o mesmo padrão com os componentes recebendo updates sobrepostos. Outro sinal é o tempo de resposta percebido. Se o usuário clica em algo e a interface demora mais de 100 milissegundos para responder, provavelmente há computação síncrona desnecessária no render path. Isso é diferente de loading real de dados. Loading de API é esperado. Lentidão após o usuário interagir com algo que já está na tela é sintoma clássico.
Também preste atenção em erros intermitentes que aparecem apenas sob certas condições de timing. Se um modal fecha sozinho, se um formulário reseta campos sem o usuário tocar neles, ou se dados aparecem e desaparecem rapidamente, o problema quase sempre é estado compartilhado entre rotas ou entre componentes que não deveriam conversar diretamente. No meu próprio projeto, o flag que me alertou foi um console.log simples colocado em cada useEffect que acessava o estado global. Em uma tela de listagem com 200 itens e três filtros ativos, eu vi o log disparar 34 vezes em dois segundos durante uma única interação de troca de categoria. Isso já era suficiente para saber que a arquitetura de estado precisava de intervenção.
O que não funciona (e por quê)
A tentação natural é otimizar prematuramente. Colocar useMemo em tudo, usar React.memo em todos os componentes, o código em lazy loading sem necessidade. Isso às vezes ajuda marginalmente, mas não resolve a raiz. Memoização em excesso pode até piorar o problema porque cria falsos caches que não invalidam quando o estado subjacente muda de forma inesperada. Também não adianta migrar para uma biblioteca de estado mais pesada. Zustand, Redux, MobX — nenhuma delas resolve spa sindrome do pensamento acelerado se a distribuição de responsabilidade do estado permanecer a mesma. A ferramenta muda, o padrão problemático continua. Eu já vi equipes inteiras gastarem semanas migrando de Redux para Zustand sem observar melhora alguma na estabilidade.
O que funciona de verdade é revisar a topologia do estado. Mapear quais dados são fonte versus quais são derivados. Definir boundaries claros entre escopos. E, acima de tudo, evitar que um único component tree dependa de mais de três fontes de estado diferentes. Se seu projeto já está em produção e a refratização completa não é viável no curto prazo, uma saída intermediária é criar uma camada de seleção com cache. Em React, isso pode ser feito com uma hook customizada que agrupa as consultas de estado e retorna um objeto memoizado. Em Vue, use composables com computed agrupados. O ganho não é tão limpo quanto uma refatoração completa, mas costuma reduzir o número de re-renderizações em 60 a 80 por cento em projetos existentes.
Cada caso é diferente. Se você tiver um projeto específico e quiser discutir a topologia de estado dele, posso dar uma olhada. Mas sem ver o código, qualquer conselho genérico tem limites claros de utilidade.