Mantendo Componentes Puros
Algumas funções JavaScript são puras. Funções puras apenas executam um cálculo e nada mais. Escrevendo seus componentes estritamente como funções puras, você pode evitar toda uma classe de erros desconcertantes e comportamento imprevisível à medida que seu código base cresce. No entanto, para obter esses benefícios, existem algumas regras que você deve seguir.
Você aprenderá
- O que é pureza e como ela ajuda você a evitar erros
- Como manter os componentes puros, mantendo as alterações fora da fase de renderização
- Como usar o Modo Estrito para encontrar erros em seus componentes
Pureza: Componentes como fórmulas
Em 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 de seus próprios negócios. Ela não altera nenhum objeto ou variável que existia antes de ela ser chamada.
- Mesmas entradas, mesma saída. Dadas as mesmas entradas, uma função pura deve sempre retornar o mesmo resultado.
Você pode já estar familiarizado com um exemplo de funções puras: fórmulas em 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 às vezes não será 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 sempre será 6.
Se fizé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
, ela retornará 6
. Sempre.
React é projetado em torno desse 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á de chá e {0.5 * drinkers} colheres de chá de especiaria.</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
, ele retornará JSX contendo 2 xícaras de água
. Sempre.
Se você passar drinkers={4}
, ele retornará JSX contendo 4 xícaras de água
. Sempre.
Assim como uma fórmula matemática.
Você pode pensar em seus componentes como receitas: se você as seguir 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 ser sempre puro. Os 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 essa regra:
let guest = 0; function Cup() { // Ruim: mudando uma variável pré-existente! guest = guest + 1; return <h2>Xícara de chá para o 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 várias vezes produzirá diferentes JSX! E o que é mais, se outros componentes lerem guest
, eles também produzirão diferentes JSX 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 podem falhar, nossos usuários ficariam perplexos, os aviões cairiam do céu — você pode ver como isso levaria a erros confusos!
Você pode corrigir este componente passando guest
como uma prop em vez disso:
function Cup({ guest }) { return <h2>Xícara de chá para o 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 só depende da prop guest
.
Em geral, você não deve esperar que seus componentes sejam renderizados em nenhuma ordem específica. Não importa se você chama y = 2x antes ou depois de y = 5x: ambas as fórmulas serão resolvidas independentemente uma da outra. Da mesma forma, cada componente deve apenas “pensar por si mesmo” e não tentar coordenar ou depender de outros durante a renderização. A renderização é como um exame escolar: cada componente deve calcular JSX sozinho!
Deep Dive
Embora você possa não ter usado todos eles ainda, no React existem três tipos de entradas que você pode ler ao renderizar: props, state e context. Você sempre deve tratar essas entradas como somente leitura.
Quando você deseja alterar algo em resposta à entrada do usuário, você deve definir o state em vez de escrever em uma variável. Você nunca deve alterar variáveis ou objetos pré-existentes enquanto seu componente está renderizando.
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 do componente 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 altera o que é retornado, e resolver y = 2x duas vezes não altera o que é y. Mesmas entradas, mesmas saídas. Sempre.
O Modo Estrito não tem efeito em produção, por isso não diminuirá a velocidade do aplicativo para seus usuários. Para participar do Modo Estrito, você pode envolver seu componente raiz em <React.StrictMode>
. Algumas estruturas fazem isso por padrão.
Mutação local: O pequeno segredo do seu componente
No exemplo acima, o problema era que o componente alterava uma variável pré-existente durante a renderização. Isso geralmente é chamado de “mutação” para fazê-lo 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 aceitável alterar variáveis e objetos que você acabou de criar durante a renderização. Neste exemplo, você cria uma array []
, atribui a ela a variável cups
e, em seguida, push
uma dúzia de xícaras nela:
function Cup({ guest }) { return <h2>Xícara de chá para o convidado #{guest}</h2>; } export default function TeaGathering() { let cups = []; for (let i = 1; i <= 12; i++) { cups.push(<Cup key={i} guest={i} />); } return cups; }
Se a variável cups
ou a array []
fossem criadas fora da função TeaGathering
, isso seria um grande problema! Você estaria alterando um objeto pré-existente inserindo itens nessa array.
No entanto, está tudo bem porque você os criou durante a mesma renderização, dentro de TeaGathering
. Nenhum código fora de TeaGathering
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 fortemente da pureza, em algum momento, em algum lugar, algo tem que mudar. Esse é 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 “à parte”, não durante a renderização.
No React, efeitos colaterais geralmente pertencem a manipuladores de eventos. Os manipuladores de eventos são funções que o React executa quando você executa alguma ação — por exemplo, ao clicar em um botão. Embora os manipuladores de eventos sejam definidos dentro do seu componente, eles não são executados durante a renderização! Portanto, 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 certo para seu efeito colateral, você ainda pode anexá-lo ao seu JSX retornado com uma chamada useEffect
em seu componente. Isso diz ao React para executá-lo mais tarde, após a renderização, quando os efeitos colaterais são permitidos. No entanto, essa abordagem deve ser seu último recurso.
Quando possível, tente expressar sua lógica apenas com a renderização. Você ficará surpreso com o quão longe isso pode te levar!
Deep Dive
Escrever funções puras requer um certo hábito e disciplina. Mas também abre oportunidades maravilhosas:
- Seus componentes podem ser executados em um ambiente diferente — por exemplo, no servidor! Como eles retornam o mesmo resultado para as mesmas entradas, um componente pode atender a muitas solicitações de usuários.
- Você pode melhorar o desempenho ignorando a renderização de componentes cujas entradas não foram alteradas. Isso é seguro porque as funções puras sempre retornam os mesmos resultados, por isso são seguras para cache.
- Se alguns dados forem alterados no meio da renderização de uma árvore de componentes profunda, o React pode reiniciar a renderização sem perder tempo para terminar a renderização desatualizada. A pureza torna seguro parar de calcular a qualquer momento.
Cada novo recurso do React que estamos construindo tira proveito da pureza. Da obtenção de dados a animações e desempenho, manter os componentes puros desbloqueia o poder do paradigma React.
Recap
- Um componente deve ser puro, o que significa:
- Ele cuida de seus próprios negócios. 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, portanto, 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” o 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 as coisas”, geralmente vai querer fazê-lo em um manipulador de eventos. Como último recurso, você pode usar
useEffect
. - Escrever funções puras leva um pouco de prática, mas desbloqueia o poder do paradigma do React.
Challenge 1 of 3: Consertar um relógio quebrado
Este componente tenta definir a classe CSS do <h1>
para "night"
durante o horário da meia-noite às seis 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 alterando temporariamente o fuso horário do computador. Quando a hora atual estiver entre meia-noite e seis da manhã, o relógio deve ter cores invertidas!
export default function Clock({ time }) { let 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> ); }