4 min

Modelos mentais do React: formas de pensar ao estilo Dan Abramov

Modelos mentais do React deixam o React simples: aprenda as ideias-chave sobre componentes, render, estado e efeitos, e aplique-as para construir UI rapidamente via chat.

Modelos mentais do React: formas de pensar ao estilo Dan Abramov

Por que o React parece difícil até você ter os modelos mentais certos

O React pode ser frustrante no começo porque você vê a UI mudar, mas nem sempre consegue explicar por que mudou. Você clica em um botão, algo atualiza e então outra parte da página te surpreende. Normalmente não é “o React é estranho”. É “a minha imagem do que o React está fazendo está borrada”.

Um modelo mental é a história simples que você conta para si mesmo sobre como algo funciona. Se a história estiver errada, você tomará decisões confiantes que levam a resultados confusos. Pense em um termostato: um modelo ruim é “eu ajusto para 22°C, então o quarto vira 22°C instantaneamente.” Um modelo melhor é “eu ajusto um alvo, e o aquecedor liga e desliga ao longo do tempo para alcançá-lo.” Com a história melhor, o comportamento deixa de parecer aleatório.

O React funciona do mesmo jeito. Depois de adotar algumas ideias claras, o React se torna previsível: você pode olhar os dados atuais e adivinhar de forma confiável o que estará na tela.

Dan Abramov ajudou a popularizar essa mentalidade de “tornar previsível”. O objetivo não é memorizar regras. É manter um pequeno conjunto de verdades na cabeça para que você debuge raciocinando, não por tentativa e erro.

Mantenha estas ideias em mente:

  • A UI é resultado do state, não um conjunto de edições manuais do DOM.
  • Componentes são funções que descrevem como a UI deve ser.
  • Dados fluem para baixo; mudanças sobem via eventos.
  • Efeitos são separados da renderização e têm um propósito específico.

Segure isso e o React deixa de parecer mágica. Passa a ser um sistema em que você pode confiar.

Componentes, props e state: a imagem central

O React fica mais fácil quando você para de pensar em “telas” e começa a pensar em pedaços pequenos. Um componente é uma unidade reutilizável de UI. Ele recebe entradas e retorna uma descrição de como a UI deve ficar para aquelas entradas.

Ajuda tratar um componente como uma descrição pura: “dado estes dados, mostre isso.” Essa descrição pode ser usada em muitos lugares porque não depende de onde o componente vive.

Props são as entradas. Elas vêm de um componente pai. Props não são “posse” do componente, e não é algo que o componente deva mudar silenciosamente. Se um botão recebe label="Save", o trabalho do botão é renderizar esse label, não decidir que ele deveria ser diferente.

State é dado possuído. É o que o componente lembra ao longo do tempo. O state muda quando o usuário interage, quando uma requisição termina ou quando você decide que algo deve ser diferente. Ao contrário das props, o state pertence àquele componente (ou ao componente que você escolher para ser o dono).

Versão direta da ideia chave: a UI é uma função do state. Se o state diz “loading”, mostre um spinner. Se o state diz “error”, mostre uma mensagem. Se o state diz “items = 3”, renderize três linhas. Seu trabalho é manter a UI lendo do state, não derivando para variáveis escondidas.

Uma forma rápida de separar os conceitos:

  • Component: o pedaço de UI (SearchBox, ProfileCard, CheckoutForm)
  • Props: o que ele precisa para mostrar (name, price, disabled)
  • State: o que ele lembra (isOpen, query, selectedId)

Exemplo: um modal. O pai pode passar title e onClose como props. O modal pode possuir isAnimating como state.

Mesmo se você estiver gerando UI por chat (por exemplo no Koder.ai), essa separação ainda é a forma mais rápida de não perder a cabeça: decida o que é props vs state primeiro, depois deixe a UI seguir.

Renderização e re-renderização: o que realmente muda

Uma forma útil de manter o React na cabeça (muito no espírito do Dan Abramov) é: renderizar é um cálculo, não um trabalho de pintura. O React executa suas funções de componente para descobrir como a UI deve ficar com os props e state atuais. A saída é uma descrição da UI, não pixels.

Um re-render só significa que o React repete aquele cálculo. Não quer dizer “a página inteira é redesenhada.” O React compara o novo resultado com o anterior e aplica o menor conjunto de mudanças no DOM real. Muitos componentes podem re-renderizar enquanto apenas alguns nós do DOM realmente mudam.

A maioria dos re-renders acontece por alguns motivos simples: o state de um componente mudou, suas props mudaram, ou um pai re-renderizou e o React pediu ao filho para renderizar novamente. Esse último surpreende as pessoas, mas normalmente tudo bem. Se você tratar render como “barato e monótono”, seu app continua mais fácil de entender.

A regra prática que mantém isso limpo: torne o render puro. Dadas as mesmas entradas (props + state), seu componente deve retornar a mesma descrição da UI. Mantenha surpresas fora do render.

Exemplo concreto: se você gerar um ID com Math.random() dentro do render, um re-render vai mudá-lo e de repente uma checkbox perde foco ou um item da lista remonta. Crie o ID uma vez (state, memo, ou fora do componente) e o render fica estável.

Se lembrar de uma frase: um re-render significa “recalcular como a UI deve ser”, não “reconstruir tudo”.

Atualizações de state: mantenha mudanças pequenas e previsíveis

Outro modelo útil: atualizações de state são pedidos, não atribuições instantâneas. Quando você chama um setter como setCount(count + 1), você está pedindo ao React para agendar um render com um novo valor. Se você ler o state logo em seguida, pode ainda ver o valor antigo porque o React ainda não fez o render.

Por isso importam atualizações “pequenas e previsíveis”. Prefira descrever a mudança em vez de pegar o que você acha que é o valor atual. Quando o próximo valor depende do anterior, use a forma updater: setCount(c => c + 1). Isso bate com o modo como o React funciona: várias atualizações podem ser enfileiradas e então aplicadas em ordem.

Imutabilidade é a outra metade da imagem. Não altere objetos e arrays no lugar. Crie um novo com a mudança. Assim o React pode ver “este valor é novo” e seu cérebro consegue rastrear o que mudou.

Exemplo: alternar um todo. A abordagem segura é criar um novo array e um novo objeto todo para o item que você mudou. A abordagem arriscada é trocar todo.done = !todo.done dentro do array existente.

Também mantenha o state mínimo. Uma armadilha comum é armazenar valores que você pode calcular. Se você já tem items e filter, não guarde filteredItems no state. Calcule durante o render. Menos variáveis de state significam menos formas de os valores saírem de sincronia.

Um teste simples para o que pertence ao state:

  • Armazene se pode mudar ao longo do tempo e a UI precisa reagir.
  • Não armazene se pode ser derivado de outro state ou props.
  • Não armazene duplicatas da mesma verdade em dois lugares.

Se você está construindo UI via chat (incluindo no Koder.ai), peça mudanças como patches pequenos: “Adicione uma flag booleana” ou “Atualize esta lista imutavelmente.” Mudanças pequenas e explícitas mantêm o gerador e seu código React alinhados.

Efeitos são para sincronizar, não para lógica básica de UI

Vá da ideia ao ar
Envie seu app React com hosting e deploys quando estiver pronto para compartilhar.

Renderizar descreve a UI. Efeitos sincronizam com o mundo exterior. “Externo” significa coisas que o React não controla: chamadas de rede, timers, APIs do navegador e às vezes trabalho imperativo no DOM.

Se algo pode ser calculado a partir de props e state, normalmente não deveria viver em um efeito. Colocar isso em um efeito adiciona um segundo passo (render, rodar efeito, set state, render de novo). Esse salto extra é onde aparecem piscadas, loops e bugs do tipo “por que isso está obsoleto?”.

Uma confusão comum: você tem firstName e lastName, e guarda fullName no state usando um efeito. Mas fullName não é um efeito colateral. É dado derivado. Calcule durante o render e ele sempre vai bater.

Como hábito: derive valores de UI durante o render (ou com useMemo quando algo for realmente custoso), e use efeitos para “fazer algo” externo, não para “descobrir algo”.

O array de dependências é uma lista de gatilhos

Trate o array de dependências como: “Quando esses valores mudarem, re-sincronize com o mundo exterior.” Não é um truque de performance e não é um lugar para silenciar avisos.

Exemplo: se você busca detalhes do usuário quando userId muda, userId pertence ao array de dependências porque deve disparar a sincronização. Se o efeito usa token também, inclua-o, ou você pode buscar com um token antigo.

Um bom teste intuitivo: se remover um efeito só deixaria a UI errada, provavelmente não era um efeito real. Se removê-lo pararia um timer, cancelaria uma assinatura ou impediria um fetch, então provavelmente era um efeito.

Perguntas frequentes

Qual é o modelo mental mais simples para tornar o React previsível?

Um bom modelo inicial é: UI = f(state, props). Seus componentes não “editam o DOM”; eles descrevem o que deve estar na tela para os dados atuais. Se a tela estiver errada, inspecione o state/props que a gerou, não o DOM.

Como decidir se algo deve ser prop ou state?

Props são entradas de um pai; seu componente deve tratá-las como somente leitura. State é memória pertencente a um componente (ou ao componente que você escolheu como dono). Se um valor precisa ser compartilhado, eleve-o e passe-o como props.

Quando o React “re-renderiza”, ele está reconstruindo a página toda?

Um re-render significa que o React re-executa sua função de componente para calcular a próxima descrição da UI. Não quer dizer que a página inteira foi repintada automaticamente. O React então atualiza o DOM real com o menor conjunto de mudanças necessário.

Por que meu state parece “um passo atrás” depois de chamar setState?

Porque as atualizações de state são agendadas, não atribuições imediatas. Se o próximo valor depende do anterior, use a forma updater para não depender de um valor possivelmente obsoleto:

  • setCount(c => c + 1)

Isso continua correto mesmo se várias atualizações estiverem na fila.

Como evitar bugs de “state derivado”?

Evite armazenar qualquer coisa que você possa calcular a partir das entradas existentes. Armazene as entradas e derive o resto durante o render.

Exemplos:

  • Armazene: items, filter
  • Derive: visibleItems = items.filter(...)

Isso evita que valores fiquem fora de sincronia.

Quando devo usar useEffect, e quando devo evitá-lo?

Use efeitos para sincronizar com coisas que o React não controla: fetch, assinaturas, timers, APIs do browser ou trabalho imperativo no DOM.

Não use um efeito apenas para calcular valores da UI a partir do state—calcule isso durante o render (ou com useMemo se for caro).

Qual é a maneira correta de pensar sobre o array de dependências do useEffect?

Trate as dependências como uma lista de gatilho: “quando esses valores mudarem, re-sincronize”. Inclua todo valor reativo que o efeito lê.

Se deixar algo de fora, você corre o risco de dados obsoletos (como um userId ou token antigo). Se acrescentar coisas erradas, pode criar loops—frequentemente sinal de que o trabalho do efeito pertence a handlers ou ao render.

Como eu sei quando elevar o state?

Se duas partes da UI precisam sempre concordar, coloque o state no pai comum mais próximo, passe o valor para baixo e passe callbacks para cima.

Um teste rápido: se você está duplicando o mesmo valor em dois componentes e escrevendo efeitos para “mantê-los sincronizados”, provavelmente esse state precisa de um dono único.

Por que meus handlers às vezes usam valores obsoletos?

Geralmente acontece quando um handler “captura” um valor antigo de uma renderização anterior. Correções comuns:

  • Use setters com updater: setX(prev => ...)
  • Coloque valores mutáveis em state/refs, não em variáveis simples
  • Garanta que efeitos listem os valores que leem

Se um clique usa “o valor de ontem”, suspeite de um fechamento obsoleto.

Como posso construir UI React rapidamente via chat sem criar state bagunçado?

Comece com um pequeno plano: componentes, donos do state e eventos. Gere código como pequenos patches (adicione um campo de state, adicione um handler, derive um valor) em vez de reescritas grandes.

Se usar um construtor por chat como Koder.ai, peça:

  • um dono claro por valor de state
  • valores derivados calculados no render
  • efeitos apenas para sincronizar (fetch/URL/storage), não para ligar a UI básica

Isso mantém o código gerado alinhado com o modelo mental do React.

Related posts