Mantendo Componentes Puros
Algumas funções JavaScript são puras. Funções puras apenas realizam um cálculo e nada mais. Ao escrever estritamente seus componentes apenas como funções puras, você pode evitar uma classe inteira de bugs desconcertantes e comportamentos imprevisíveis conforme sua base de código cresce. Para obter esses benefícios, no entanto, há algumas regras que você deve seguir.
Você aprenderá
- O que é pureza e como ela ajuda você a evitar bugs
- Como manter componentes puros mantendo mudanças fora da fase de renderização
- Como usar o Modo Estrito para encontrar erros em seus componentes
Pureza: Componentes como fórmulas
Na ciência da computação (e especialmente no mundo da programação funcional), uma função pura é uma função com as seguintes características:
- Ela cuida apenas dos seus próprios assuntos. Ela não altera nenhum objeto ou variável que existia antes de ser chamada.
- Mesmas entradas, mesma saída. Dadas as mesmas entradas, uma função pura sempre deve retornar o mesmo resultado.
Você pode já estar familiarizado com um exemplo de funções puras: fórmulas na matemática.
Considere esta fórmula matemática: y = 2x.
Se x = 2 então y = 4. Sempre.
Se x = 3 então y = 6. Sempre.
Se x = 3, y não será às vezes 9 ou –1 ou 2.5 dependendo da hora do dia ou do estado do mercado de ações.
Se y = 2x e x = 3, y será sempre 6.
Se transformássemos isso em uma função JavaScript, ficaria assim:
function double(number) {
return 2 * number;
}
No exemplo acima, double
é uma função pura. Se você passar 3
para ela, ela retornará 6
. Sempre.
React é projetado em torno deste conceito. React assume que todo componente que você escreve é uma função pura. Isso significa que os componentes React que você escreve devem sempre retornar o mesmo JSX dadas as mesmas entradas:
function Recipe({ drinkers }) { return ( <ol> <li>Ferva {drinkers} xícaras de água.</li> <li>Adicione {drinkers} colheres de chá e {0.5 * drinkers} colheres de especiarias.</li> <li>Adicione {0.5 * drinkers} xícaras de leite para ferver e açúcar a gosto.</li> </ol> ); } export default function App() { return ( <section> <h1>Receita de Chai com Especiarias</h1> <h2>Para dois</h2> <Recipe drinkers={2} /> <h2>Para uma reunião</h2> <Recipe drinkers={4} /> </section> ); }
Quando você passa drinkers={2}
para Recipe
, ela retornará JSX contendo 2 xícaras de água
. Sempre.
Se você passar drinkers={4}
, ela retornará JSX contendo 4 xícaras de água
. Sempre.
Assim como uma fórmula matemática.
Você poderia pensar nos seus componentes como receitas: se você segui-las e não introduzir novos ingredientes durante o processo de cozimento, você obterá o mesmo prato toda vez. Esse “prato” é o JSX que o componente serve ao React para renderizar.

Illustrated by Rachel Lee Nabors
Efeitos colaterais: consequências (não)intencionais
O processo de renderização do React deve sempre ser puro. Componentes devem apenas retornar seu JSX, e não alterar nenhum objeto ou variável que existia antes da renderização—isso os tornaria impuros!
Aqui está um componente que quebra esta regra:
let guest = 0; function Cup() { // Ruim: alterando uma variável pré-existente! guest = guest + 1; return <h2>Xícara de chá para convidado #{guest}</h2>; } export default function TeaSet() { return ( <> <Cup /> <Cup /> <Cup /> </> ); }
Este componente está lendo e escrevendo uma variável guest
declarada fora dele. Isso significa que chamar este componente múltiplas vezes produzirá JSX diferente! E mais ainda, se outros componentes lerem guest
, eles também produzirão JSX diferente, dependendo de quando foram renderizados! Isso não é previsível.
Voltando à nossa fórmula y = 2x, agora mesmo se x = 2, não podemos confiar que y = 4. Nossos testes poderiam falhar, nossos usuários ficariam perplexos, aviões cairiam do céu—você pode ver como isso levaria a bugs confusos!
Você pode corrigir este componente passando guest
como uma prop em vez disso:
function Cup({ guest }) { return <h2>Xícara de chá para convidado #{guest}</h2>; } export default function TeaSet() { return ( <> <Cup guest={1} /> <Cup guest={2} /> <Cup guest={3} /> </> ); }
Agora seu componente é puro, pois o JSX que ele retorna depende apenas da prop guest
.
Em geral, você não deve esperar que seus componentes sejam renderizados em uma ordem específica. Não importa se você chamar y = 2x antes ou depois de y = 5x: ambas as fórmulas se resolverão independentemente uma da outra. Da mesma forma, cada componente deve apenas “pensar por si mesmo”, e não tentar se coordenar com ou depender de outros durante a renderização. A renderização é como um exame escolar: cada componente deve calcular JSX por conta própria!
Deep Dive
Embora você talvez ainda não tenha usado todos eles, no React existem três tipos de entradas que você pode ler durante a renderização: props, state, e context. Você deve sempre tratar essas entradas como somente leitura.
Quando você quiser alterar algo em resposta à entrada do usuário, você deve definir state em vez de escrever em uma variável. Você nunca deve alterar variáveis ou objetos pré-existentes enquanto seu componente está renderizando.
O React oferece um “Modo Estrito” no qual ele chama a função de cada componente duas vezes durante o desenvolvimento. Ao chamar as funções dos componentes duas vezes, o Modo Estrito ajuda a encontrar componentes que quebram essas regras.
Observe como o exemplo original exibiu “Convidado #2”, “Convidado #4”, e “Convidado #6” em vez de “Convidado #1”, “Convidado #2”, e “Convidado #3”. A função original era impura, então chamá-la duas vezes a quebrou. Mas a versão pura corrigida funciona mesmo se a função for chamada duas vezes toda vez. Funções puras apenas calculam, então chamá-las duas vezes não mudará nada—assim como chamar double(2)
duas vezes não muda o que é retornado, e resolver y = 2x duas vezes não muda o que y é. Mesmas entradas, mesmas saídas. Sempre.
O Modo Estrito não tem efeito em produção, então não deixará o aplicativo mais lento para seus usuários. Para optar pelo Modo Estrito, você pode envolver seu componente raiz em <React.StrictMode>
. Alguns frameworks fazem isso por padrão.
Mutação local: O pequeno segredo do seu componente
No exemplo acima, o problema era que o componente alterou uma variável pré-existente durante a renderização. Isso é frequentemente chamado de “mutação” para soar um pouco mais assustador. Funções puras não mutam variáveis fora do escopo da função ou objetos que foram criados antes da chamada—isso as torna impuras!
No entanto, é perfeitamente normal alterar variáveis e objetos que você acabou de criar durante a renderização. Neste exemplo, você cria um array []
, o atribui a uma variável cups
, e então faz push
de uma dúzia de xícaras nele:
function Cup({ guest }) { return <h2>Xícara de chá para convidado #{guest}</h2>; } export default function TeaGathering() { const cups = []; for (let i = 1; i <= 12; i++) { cups.push(<Cup key={i} guest={i} />); } return cups; }
Se a variável cups
ou o array []
fossem criados fora da função TeaGathering
, isso seria um grande problema! Você estaria alterando um objeto pré-existente empurrando itens para esse array.
No entanto, está tudo bem porque você os criou durante a mesma renderização, dentro de TeaGathering
. Nenhum código fora de TeaGathering
jamais saberá que isso aconteceu. Isso é chamado de “mutação local”—é como o pequeno segredo do seu componente.
Onde você pode causar efeitos colaterais
Embora a programação funcional dependa muito da pureza, em algum ponto, em algum lugar, alguma coisa tem que mudar. Esse é meio que o ponto da programação! Essas mudanças—atualizar a tela, iniciar uma animação, alterar os dados—são chamadas de efeitos colaterais. São coisas que acontecem “ao lado”, não durante a renderização.
No React, efeitos colaterais geralmente pertencem dentro de manipuladores de eventos. Manipuladores de eventos são funções que o React executa quando você realiza alguma ação—por exemplo, quando você clica em um botão. Mesmo que os manipuladores de eventos sejam definidos dentro do seu componente, eles não executam durante a renderização! Então os manipuladores de eventos não precisam ser puros.
Se você esgotou todas as outras opções e não consegue encontrar o manipulador de eventos correto para seu efeito colateral, você ainda pode anexá-lo ao seu JSX retornado com uma chamada useEffect
no seu componente. Isso diz ao React para executá-lo mais tarde, após a renderização, quando efeitos colaterais são permitidos. No entanto, esta abordagem deve ser seu último recurso.
Quando possível, tente expressar sua lógica apenas com renderização. Você ficará surpreso com o quão longe isso pode levá-lo!
Deep Dive
Escrever funções puras exige algum hábito e disciplina. Mas também desbloqueiam oportunidades maravilhosas:
- Seus componentes poderiam executar em um ambiente diferente—por exemplo, no servidor! Como eles retornam o mesmo resultado para as mesmas entradas, um componente pode servir muitas solicitações de usuários.
- Você pode melhorar a performance pulando a renderização de componentes cujas entradas não mudaram. Isso é seguro porque funções puras sempre retornam os mesmos resultados, então são seguras para cache.
- Se alguns dados mudarem no meio da renderização de uma árvore de componentes profunda, o React pode reiniciar a renderização sem desperdiçar tempo para terminar a renderização desatualizada. A pureza torna seguro parar de calcular a qualquer momento.
Todo novo recurso do React que estamos construindo aproveita a pureza. Da busca de dados às animações à performance, manter componentes puros desbloqueiam o poder do paradigma React.
Recap
- Um componente deve ser puro, significando:
- Ele cuida apenas dos seus próprios assuntos. Ele não deve alterar nenhum objeto ou variável que existia antes da renderização.
- Mesmas entradas, mesma saída. Dadas as mesmas entradas, um componente deve sempre retornar o mesmo JSX.
- A renderização pode acontecer a qualquer momento, então os componentes não devem depender da sequência de renderização uns dos outros.
- Você não deve mutar nenhuma das entradas que seus componentes usam para renderização. Isso inclui props, state, e context. Para atualizar a tela, “defina” state em vez de mutar objetos pré-existentes.
- Esforce-se para expressar a lógica do seu componente no JSX que você retorna. Quando você precisar “mudar coisas”, você geralmente vai querer fazer isso em um manipulador de eventos. Como último recurso, você pode usar
useEffect
. - Escrever funções puras exige um pouco de prática, mas desbloqueiam o poder do paradigma do React.
Challenge 1 of 3: Conserte um relógio quebrado
Este componente tenta definir a classe CSS do <h1>
para "night"
durante o horário da meia-noite às seis horas da manhã, e "day"
em todos os outros horários. No entanto, não funciona. Você pode consertar este componente?
Você pode verificar se sua solução funciona mudando temporariamente o fuso horário do computador. Quando o horário atual estiver entre meia-noite e seis da manhã, o relógio deve ter cores invertidas!
export default function Clock({ time }) { const hours = time.getHours(); if (hours >= 0 && hours <= 6) { document.getElementById('time').className = 'night'; } else { document.getElementById('time').className = 'day'; } return ( <h1 id="time"> {time.toLocaleTimeString()} </h1> ); }