DEV Community

Cover image for Hook useCallback - Entenda quando utiliza-lo?
Guilherme Selair
Guilherme Selair

Posted on • Updated on

Hook useCallback - Entenda quando utiliza-lo?

Salve Salve! 🖖🏻 Voltei depois de muitoooo tempo 😅.

Dessa vez vim falar um pouco sobre um dos famosos hooks do React, useCallback. Percebo que ele gera muita dúvida em quem esta iniciando em React e até mesmo desenvolvedores que já atuam com ele.

A ideia deste post é apresentar um pouco sobre a minha visão deste hook para quem não conhece e esclarecer onde ele pode ser aplicado assim como aplica-lo na pratica.

Este é o começo de uma série de posts falando um pouco mais sobre a minha visão sobre os hooks disponibilizados pelo React.

https://media.giphy.com/media/BYS6j7XxxyvTi/giphy.gif

Nota
Este post não serve de documentação e não tem como objetivo ser o mais completo possível. Ele representa apenas a minha visão sobre a utilização do useCallback que obtive ao longo do tempo.


Introdução

A partir do React 16 foram disponibilizados uma série de hooks nativos que buscam facilitar o desenvolvimento de componentes funcionais. Desses hooks falaremos neste post sobre useCallback.

useCallback

Este hook recebe dois parâmetros, uma função callback e um array de dependências. O seu retorno é uma versão memoizada da função callback recebida como primeiro parâmetro. De forma básica quando me refiro em uma versão memoizada podemos nos referir a uma versão memorizada ou “cacheada” da função.

Obs: Aqui vale ressaltar um ponto bem importante, o retorno deste hook é uma versão memoizada da função e não do resultado da função. Isso quer dizer que a função só vai ser executada quando você utiliza-la desta maneira: minhaFuncao()

Como este callback é uma versão memoizada é preciso informar quando essa função deve ser recalculada para que valores atualizados sejam utilizados. É por isso que existe o array de dependências passado como segundo parâmetro para hook. Os valores passado dentro deste array são o que fazem a função callback ser recalculada. Normalmente variáveis externas a função de callback que são utilizadas dentro da função, estarão neste array. Caso você não informe as variáveis que são utilizadas dentro da função, a grandes chances delas estarem com seus valores desatualizados quando a função for disparada.

Abaixo temos um exemplo da sintaxe deste hook:

import { useCallback } from 'react';

const handleClick = useCallback(async () => {
    await sendMail(address)
}, [address]);

...

return <button ... onClick={handleSubmit}>Enviar email</button>
Enter fullscreen mode Exit fullscreen mode

https://media.giphy.com/media/L3FInpXg6pGEGXPR0a/giphy.gif

Beleza, mas quando utilizar?

Essa é uma pergunta super interessante e importante, porque o uso em excesso ou da maneira incorreta ao utilizar o useCallback pode ser pior que utilizar uma simples função comum.

Este hook vem pra nos ajudar a melhorar a performance de nossas aplicações mas ao mesmo tempo se utilizarmos de maneira incorreta, estaremos adicionando mais passos/lógicas em nossas funções. Isso porque antes de retornar uma versão memoizada da função, o hook faz uma comparação para saber se ele deve ou não recalcular aquela versão para então retornar a versão atualizada do callback.

Obs: O React já é uma biblioteca muito rápida e eficiente, então em grande parte dos casos, nem iremos notar essas adições de lógicas em nossa aplicação.

Então voltamos a pergunta, quando devo utilizar este hook? A resposta é apenas uma: Quando você precisar manter a igualdade referencial.

Você já deve ter escutado bastante sobre renderizações no universo do React. Quando essas renderizações ocorrem sejam por conta que o componente pai alterou, uma propriedade alterou ou algum estado foi alterado, em todos esses casos os componentes em questão entram em processo de renderização. Isso quer dizer que pelo menos uma comparação entre o componente anterior a renderização e o mesmo componente com os dados alterados é realizada.

Nesse processo novos blocos de memória (referências) são utilizados para atualizar variáveis/funções. E aqui entra um grande ponto se você já testou comparações no Javascript. Pois ao fazer a seguinte comparação:

let a = function(){}
let b = function(){}

a === b // false
Enter fullscreen mode Exit fullscreen mode

Isso retornará false . Essa comparação apenas será true se a referência das funções forem a mesma. Como a gente pode ver abaixo:

Shallow Compare functions

Podemos notar que apenas quando atribuímos a variável a a variável b que a comparação entre as duas funções deu true. Ou seja, elas utilizam a mesma referência.

Ter noção disso é muito importante porque pode evitar que algumas renderizações desnecessárias ocorram. E isso não vale somente para funções mas também para objetos e arrays.


https://thumbs.gfycat.com/PaleThunderousGroundhog-max-1mb.gif

Show me the code! 🤖

Vamos parar de papo e mostrar realmente como você deve utilizar este hook. Imagine o seguinte cenário, você tem um hook de autenticação e através dele você disponibiliza duas funções signIn e signOut. Essas funções podem ser envolvidas pelo useCallback, isso porque são funções que serão utilizadas em diversos componentes da aplicação e com isso manter a igualdade referencial dessas funções é importante para que se o nosso hook de autenticação for alterado, todos os componentes que o utilizam também serão re-renderizados.

Abaixo tem um exemplo do cenário ilustrado:

AuthContext

Agora pense em outro cenário: Resolvemos refatorar nosso código e criamos um novo componente para segmentar melhor a lógica. Porém este novo componente terá que atualizar um estado que vai estar em seu componente pai. Para fazer essa atualização, podemos enviar a função que faz essa atualização do pai para o filho e dentro do filho executaríamos esta função passando como parâmetro o valor desejado.
Este é um uso importante do useCallback também. *Funções que são passadas do pai pro filho devem estar envolvidas pelo *hook.
**
Novamente aqui a principal motivação para seu uso é manter a igualdade referencial da função. Para notarmos 100% isso funcionando na prática, vamos ter que utilizar também outro hook do React, o memo.

Obs: Falaremos mais sobre este hook em outro post 😀

Abaixo tem um exemplo do cenário ilustrado:

FatherWithoutCallback

O código acima tem como retorno os seguintes consoles ao clicar no botão de counter:

FatherAndChildrenUpdated

Aqui da pra perceber que o “FILHO” só renderizou porque um estado do componente “PAI” foi alterado porém o “FILHO” não recebe o estado que foi alterado. Então você concorda comigo que ele não precisava ser re-renderizado.
Agora se ajustarmos o cenário acima com os hooks useCallback e memo, temos o seguinte resultado ao clicar no botão:

FatherUpdated

Agora o componente “FILHO” só renderizará novamente quando a versão memoizada da função for atualizada, ou seja, somente quando realmente alguma de suas propriedades alterem. O código com a altera ficou deste jeito:

FatherToChildWithCallback


Top demais! 😍

Eu espero ter ajudado você a entender um pouquinho mais sobre este hook, o que é e quando utilizar. Já passei por essas dúvidas e essas foram as minhas conclusões sobre elas.

Em breve voltarei com outros posts sobre os demais hooks que o React nos dispõem.

Valeeeeu demais pela leitura! Gostou? Ficou com dúvida? Falei alguma coisa errada? Vamos conversar melhor nos comentários

See you soon! 🖖🏻

https://media.giphy.com/media/l1J3CbFgn5o7DGRuE/giphy.gif

Referências

Top comments (1)

Collapse
 
nadoti profile image
Douglas Nadoti

Post Muito bom