Antes de tudo, é importante ressaltar: Ninguém usa mais Componentes de Classe no React, portanto, esse post é sobre renderização de Componentes Funcionais.
Componente Funcional
Um componente funcional é basicamente uma função que retorna um JSX.Element
, isto é, tags HTML com uma pitada de JavaScript.
Para declarar e exportar um componente funcional no React, basta declarar e exportar uma função.
Supondo que você saiba como funciona o useState
(Se não souber, avise nos comentários), é assim que se declara um component funcional com estado no React:
import React, { useState } from "react"
export const Contador = () => {
const [valorContador, atualizaValorContador] = useState(0)
const aumentaValor = () => {
atualizaValorContador(valorContador + 1)
}
return (
<button id="value-button" onClick={aumentaValor}>
{ valorContador }
</button>
)
}
Você também pode declarar um componente funcional utilizando a palavra-chave function
ao invés de const
:
export function Contador() {
const [valorContador, atualizaValorContador] = useState(0)
const aumentaValor = () => {
atualizaValorContador(valorContador + 1)
}
return (
<button id="value-button" onClick={aumentaValor}>
{ valorContador }
</button>
)
}
Renderização
Sempre que um estado ou propriedade do componente mudar, o código da função será executado novamente.
É crucial que você entenda 100% da frase acima, anote-a caso necessário.
Isso significa que a cada clique no 'value-button':
- O valorContador será incrementado.
- A função aumentaValor será redeclarada, criando uma nova referência na memória.
- O bloco return será executado novamente.
Ou seja, todo código da função é executado novamente!
Hook useEffect
O hook useEffect é uma função disponível no React que permite a execução de efeitos colaterais (side-effects) em componentes funcionais.
Através de uma "manobra" do EventLoop (um pouco complexo de explicar), o contexto da função roda em um estado "non-blocking", ou seja, não atrapalha na renderização do componente.
Quase como se rodasse em uma thread separada, mas não roda.
- A função é executada após a renderização do componente.
- Você controla quando o efeito será executado através meio de uma lista de dependências, passada como segundo parâmetro da função useEffect.
Agora, para demonstrar seus casos de uso, vamos supor que queremos exibir um alerta na página.
Roda sempre (Sem dependência)
Para adicionar um "side-effect" sempre que houver qualquer alteração de estado ou de propriedade no componente, basta utilizar o useEffect
sem um segundo parâmetro.
useEffect(() => {
alert('Eu sou executado sempre que o componente é renderizado')
})
Roda 1x
Rodar uma função a TODA atualização de QUALQUER estado OU prop é, na maioria das vezes, desnecessário.
Caso você queira executar uma função apenas 1x, logo após o componente ter sido renderizado, você deve utilizar o useEffect
da seguinte maneira.
useEffect(() => {
alert('Eu sou executado uma vez, depois que o componente é renderizado pela primeira vez')
}, [])
Roda sempre que [estado1, estado2] mudarem
Para efeitos colaterais específicos vinculados a um ou mais estados, você pode adicionar os estados desejados ao array de dependências do useEffect
.
useEffect(() => {
alert('Eu sou executado sempre que o valorContador mudar.')
console.log(valorContador)
}, [valorContador])
Isso é especialmente útil quando você possui mais de um estado em um componente e quer atribuir ações específicas às suas atualizações.
Por via de regra, é uma boa prática incluir apenas os estados utilizados na função callback (primeiro parâmetro) no array de dependências.
Tenha cuidado com o cenário "sem dependências", pois isso pode levar a execuções desnecessárias e problemas de performance.
Fique ligado para mais posts sobre renderização no React, onde pretendo abordar os hooks useCallback e useMemo em breve!