Desmistificando React Hooks — useCallback

Começando
Se quiser acompanhar em seu IDE local, você pode encontrar o GitHub Repo aqui .
clone
cd client
npm i
npm start
Igualdade Referencial é um conceito fundamental em JavaScript e Ciência da Computação como um todo. Então, vamos começar com uma demonstração dele em ação.
Incorporei capturas de tela ao longo do artigo para facilitar o uso em dispositivos móveis. Se você estiver na área de trabalho e o tiver clonado, execute referentialEquality.js
para observar a saída ou apenas jogue com o trecho JSFiddle incorporado abaixo.
Ao avaliar se o integer 1
é estritamente igual ao integer 1
, o console imprime true
. Isso ocorre porque, bem… o integer 1
é estritamente igual ao integer 1
.

Vemos o mesmo resultado ao avaliar duas strings.

Obviamente, este sempre será o caso para dois tipos de dados primitivos do mesmo valor.
Agora, e as estruturas de dados? Por exemplo, dois literais de objeto com os mesmos pares chave/valor? E os literais de objetos vazios?

Por que isso imprimiria false
? Ao comparar se esses dois literais de objeto são estritamente iguais, o JavaScript usa seus respectivos endereços de memória .
Em outras palavras, esses dois objetos podem conter os mesmos valores , mas não estão referenciando o mesmo objeto . Eles parecem iguais, mas ocupam dois espaços diferentes na memória .
O mesmo se aplica se você estiver comparando dois literais de objeto, dois literais de matriz ou duas funções!

Para demonstrar isso melhor, definiremos uma função func
, que retorna uma função anônima que, por sua vez, retorna outra coisa ( como um elemento JSX ).

Atribuiremos então duas funções diferentes, firstRender
e secondRender
, igual ao valor retornado por func
.

Pense func
como seu componente funcional React, enquanto firstRender
é uma função dentro dele na primeira renderização e secondRender
é uma função dentro dele na segunda renderização.
Mesmo que firstRender
e secondRender
retornem o mesmo valor e sejam atribuídos a partir da mesma definição, eles não possuem igualdade referencial . Como resultado, toda vez que o componente renderiza, ele redefine essa função.

Infelizmente, em JavaScript, não é fácil imprimir esses endereços de memória como em Python, mas para uma explicação um pouco mais aprofundada de referência versus valor, dê uma olhada neste artigo do freeCodeCamp.
Este tópico pode ficar denso e você não precisa dar uma aula sobre ele esta noite. Então, por enquanto, lembre-se:
- tipo de dado primitivo
===
tipo de dado primitivo - estrutura de dados
!==
estrutura de dados.
Código inicial
Depois de ativar nosso aplicativo, abra o BookDetails.jsx
componente e salve novamente. A primeira coisa que podemos notar em nosso servidor de desenvolvimento React é algo comum WARNING
que os jovens desenvolvedores tendem a ignorar. À medida que você atinge a força de trabalho e começa a escrever código para produção, seus linters serão ainda mais rígidos do que o que está embutido no create-react-app
. WARNINGS
irá virar para ERRORS
, e alguns linters não permitirão que você empurre antes de endereçá-los ERRORS
.
Portanto, em vez de ignorá-lo, vamos descobrir como tratá-lo.

NOTA: você pode primeiro precisar salvar novamente BookDetails.jsx
para criar esteWARNING
Se nos aprofundarmos no React Docs , podemos decodificar as soluções propostas semiconfusas para isso WARNING
da seguinte forma:
1. Inclua a definição da função dentro do arquivo useEffect
.
- Não podemos chamar essa função em outro lugar, a menos que a redefinamos.
- Isso acionará
useEffect
toda vez que o estado ou os adereços mudarem, às vezes causando uma re-renderização infinita. E, em nosso caso, como estamos chamando nossa função de configurador de estado após uma chamada de API, isso pode sobrecarregar nossa API com infinitas solicitações de ponto de extremidade.
- A função não será chamada.
- Na primeira vez que o componente for renderizado, ele definirá nossa função, que acionará o
useEffect
, o que fará com que o componente seja renderizado novamente, o que redefinirá a função, o que acionará ouseEffect
, o que fará com que o componente seja renderizado novamente, o que irá redefinir a função…
A solução mais simples e preferida seria 'incluí-la', ou seja, mover a getBookDetails
definição da função para dentro do arquivo useEffect
. Isso segue um princípio de Programação Orientada a Objetos conhecido como Encapsulamento .
Mas digamos que sabemos que precisamos chamar a função em outro lugar. Devemos redefini-lo mais tarde? Isso não é muito seco de nós.
Vamos alterar nosso array de dependências para incluir nossa referência de função. Agora você useEffect
deve ficar assim.

E getBookDetails
permanece definido acima do useEffect
.

Agora temos um novoWARNING

Insira o gancho useCallback
Resumindo, o useCallback
gancho permite que você armazene em cache, ou 'memoize', uma função entre as re-renderizações do seu componente. Ele executa uma tarefa semelhante a useMemo
, cujas nuances abordaremos em outro artigo.
Se o âmago da questão for do seu interesse, você pode ler mais nos documentos do React .
Observe o aviso:
Você só deve confiar useCallback
como uma otimização de desempenho. Se o seu código não funcionar sem ele, encontre o problema subjacente e corrija-o primeiro. Então você pode adicionar useCallback
para melhorar o desempenho.
useCallback
Sintaxe
useCallback
A sintaxe de ' é muito semelhante à useEffect
sintaxe de ' que já conhecemos. Olhe para os esqueletos de cada um.

A pequena diferença é com useEffect
, dizemos à função anônima para executar nossa função enquanto com useCallback
, atribuímos o valor de retorno a uma referência a ser chamada em outro lugar.
Usando useCallback
Primeiro, vamos importar useCallback
de 'react'
. Em vez de adicionar uma nova linha, é melhor desestruturar junto com nossas outras importações.

Agora podemos atribuir getBookDetails
ao valor retornado de uma useCallback
chamada de função.

Em seguida, adicionamos toda a sintaxe para useCallback
. Lembre-se de sua matriz de dependência!

Em nosso exemplo, precisamos async
antes de nossos parâmetros.

E, finalmente, adicionamos a lógica de nossa função ao bloco de código.

Depois de salvar, obtemos ... outro arquivo WARNING
.

Por que nosso array de dependências deve rastrear a id
variável?
Vamos pensar sobre isso.
- Se o valor de
id
mudar,getBookDetails
precisa atingir um ponto final diferente, então o React deve redefini-lo. A definição degetBookDetails
literalmente depende do valor deid
.

E por fim, é isso! Vemos verde em nosso servidor React dev. Um linter feliz é um desenvolvedor sênior feliz. E um Desenvolvedor Sênior feliz é um feliz você!
Estou sempre procurando novos amigos e colegas. Se você achou este artigo útil e gostaria de se conectar, você pode me encontrar em qualquer uma das minhas casas na web.
GitHub | Twitter | Linkedin | Local na rede Internet
Recursos
- Igualdade Referencial
- Tipos de dados primitivos de JavaScript vs. estruturas de dados
- Encapsulamento
useCallback
- React Docs