Injetando código no carregamento de um componente usando Hooks

30 Sep • Escrito por @lhas

É uma tarefa comum no dia-a-dia de um desenvolvedor React, precisar chamar uma função assim que um componente é montado no React.

Antes do Hooks, resolvíamos isso de uma maneira muito simples:

componentDidMount() {
    funcaoQualquer();
}

Entretanto, com a chegada dos Hooks na versão 16.8, isso mudou.

Temos uma maneira igualmente simples de fazer o processo, desta vez usando o hook de useEffect:

useEffect(() => {
  funcaoQualquer()
}, [])

Nem tudo são flores…

Contudo, se a função está vindo de uma prop (comum quando estamos usando mapDispatchToProps ou algo do tipo), você receberá o seguinte warning:

React Hook useEffect has a missing dependency: 'funcaoQualquer'. Either include it or remove the dependency array. (react-hooks/exhaustive-deps)

O primeiro instinto para tentar resolver o problema, é simplesmente inserir funcaoQualquer no array de dependências:

useEffect(() => {
  funcaoQualquer()
}, [funcaoQualquer])

No entanto, você observerá que isso desencadeará um loop infinito no seu componente.

Isso acontece por que, toda vez que o componente é renderizado, ele atualiza o valor da prop de funcaoQualquer, mesmo que o valor dela não tenha mudado.

Existe uma maneira muito simples e elegante de resolver este problema: usando o hook de useCallback.

O que é o hook de useCallback

O useCallback é um hook que recebe uma função como parâmetro. Ele irá retornar esta função numa versão memoizada.

Memoização é uma técnica de programação que procura aumentar a performance de uma função, cacheando seus valores previamente computados.

Cada vez que uma função memoizada é chamada, seus parâmetros são usados para indexar um cache. Se os parâmetros passados já existirem no cache, o seu resultado é retornado, sem executar a função completamente. Do contrário, se a função ainda não foi executada com aqueles argumentos, então a função é executada e o seu resultado é adicionado no cache.

Graças a memoização, podemos montar uma função que será acionada somente uma vez pelo nosso componente. A não ser que funcaoQualquer efetivamente mude de valor.

useCallBack na prática

Precisamos importá-lo no nosso componente:

import React, { useCallback } from "react"

Dentro do nosso componente, iremos usá-lo:

const ComponenteExemplo = ({ funcaoQualquer }) => {
  const doFuncaoQualquer = useCallback(() => {
    funcaoQualquer()
  }, [funcaoQualquer])

  useEffect(() => {
    doFuncaoQualquer()
  }, [doFuncaoQualquer])

  return <div>componente de exemplo! :D</div>
}

Ta-da! 🎉

Problema resolvido de forma elegante. Sem warnings, sem desabilitações de eslint.

Conclusão

Esta alternativa para se injetar código na inicialização do componente é descrita na página do FAQ de Hooks. Infelizmente, muitos desenvolvedores acabam se livrando do warning apenas desabilitando o exhaustive-deps, mas há maneiras mais interessantes de resolver o problema.

Recomendações de Leitura

Recomendo a página de FAQ dos Hooks e o site usehooks.com para aprender mais sobre o que são Hooks e como usá-los corretamente.


Escrito por

Luiz Almeida

Especialista em front-end, trabalha com desenvolvimento há 10 anos. Apaixonado por escrever e participar de desafios que envolvem tecnologia, vive atualmente em Porto Alegre.

LinkedIn Instagram