No desenvolvimento de software, geralmente somos obcecados com ganhos de desempenho e como fazer nossos aplicativos funcionarem mais rápido para oferecer aos usuários uma experiência melhor.
Memoização é uma das maneiras de otimizar o desempenho. Neste artigo, vamos explorar como funciona no React.
O que é memoização?
Em termos simples, a memoização é um processo que nos permite armazenar em cache os valores de chamadas de funções recursivas/caras para que na próxima vez que a função for chamada com o (s) mesmo (s) argumento (s), o valor em cache seja retornado em vez de recalcule a função.
Isso garante que nossos aplicativos sejam executados com mais rapidez, pois evitamos o tempo que normalmente levaria para reexecutar a função, retornando um valor que já está armazenado na memória.
Por que usar memoização no React?
Nos componentes funcionais do React, quando os adereços em um componente são alterados, todo o componente é renderizado novamente por padrão. Em outras palavras, se algum valor em um componente for atualizado, todo o componente será renderizado novamente, incluindo funções/componentes que não tiveram seus valores/props alterados.
Vejamos um exemplo simples de onde isso acontece. Criaremos um aplicativo básico que informa aos usuários qual vinho combina melhor com o queijo que eles selecionaram.
Começaremos configurando dois componentes. O primeiro componente permitirá ao usuário selecionar um queijo. Em seguida, exibirá o nome do vinho que combina melhor com aquele queijo. O segundo componente será filho do primeiro componente. Neste componente, nada muda. Usaremos esse componente para controlar quantas vezes o React é renderizado novamente.
Vamos começar com nosso componente pai:
.
NB , os
classNames
usados neste exemplo vêm de Tailwind CSS .
//components/parent-component.js importar contagens de"./counts"; botão de importação de"./button"; import {useState, useEffect} de"react"; importar constantes de"../utils"; const {MOZARELLA, CHEDDAR, PARMESAN, CABERNET, CHARDONAY, MERLOT}=constantes; função padrão de exportação ParentComponent () { const [cheeseType, setCheeseType]=useState (""); const [vinho, setWine]=useState (""); const whichWineGoesBest=()=> { switch (cheeseType) { case MOZARELLA: retornar setWine (CABERNET); case CHEDDAR: retornar setWine (CHARDONAY); case PARMESAN: retornar setWine (MERLOT); predefinição: CHARDONAY; } }; useEffect (()=> { deixe montado=verdadeiro; if (montado) { whichWineGoesBest (); } return ()=> (montado=falso); }, [cheeseType]); Retorna (); }Sem React.memo () ou useMemo ()
Selecione um queijo e diremos qual vinho fica melhor!
{cheeseType && (setCheeseType (MOZARELLA)}/> setCheeseType (CHEDDAR)}/> setCheeseType (PARMESAN)}/> Para {cheeseType}, {wine} {""} vai melhor.
)}
O segundo componente é um componente
que rastreia quantas vezes todo o componente
é renderizado novamente.
//components/counts.js import {useRef} de"react"; função padrão de exportação Counts () { const renderCount=useRef (0); Retorna (); }Nada mudou aqui, mas agora renderizei: {""} {(renderCount.current ++)} vez (es)
Aqui está o exemplo acima em ação quando clicamos no nome de um queijo:
Nosso componente
em nosso
conta quantas vezes as alterações no
força o
componente para renderizar novamente.
Atualmente, clicar no nome de um queijo irá atualizar o nome do queijo a ser exibido. Ele também atualizará o nome do vinho a ser exibido. Não apenas o
será renderizado novamente, mas o componente
também será renderizado novamente, mesmo que nada dentro dele tenha mudado.
Imagine ter um componente exibindo milhares de dados, e cada vez que o usuário clica em um botão, todos os dados nesse componente ou árvore são renderizados novamente quando não precisam. É aqui que React.memo ()
ou useMemo ()
se torna necessário para nos fornecer otimizações de desempenho.
Agora, vamos explorar React.memo
e, em seguida, useMemo ()
. Depois disso, compararemos as diferenças entre eles e aprenderemos quando você deve usar um em vez do outro.
O que é React.memo ()
?
React.memo ()
foi lançado com React v16.6 . Embora os componentes da classe já permitam que você controle os re-renderizadores com o uso de PureComponent
ou shouldComponentUpdate
, React 16.6 introduziu a capacidade de fazer o mesmo com componentes funcionais.
React.memo ()
é um componente de ordem superior (HOC) , que é um nome extravagante para um componente que pega um componente como um suporte e retorna um componente que evita que um componente seja renderizado novamente se os acessórios (ou valores dentro dele) tiverem não mudou.
Usaremos o mesmo exemplo acima, mas usaremos React.memo ()
em nosso componente
. Tudo o que precisamos fazer é envolver nosso componente
com React.memo ()
como abaixo:
import {useRef} de"react"; function Counts () { const renderCount=useRef (0); Retorna (); } exportar React.memo (contagens) padrão;Nada mudou aqui, mas agora renderizei: {""} {(renderCount.current ++)} vez (es)
Agora, quando selecionamos um tipo de queijo clicando nele, nosso componente
não será renderizado novamente.
O que é useMemo ()
?
Embora React.memo ()
seja um HOC, useMemo ()
é um React Hook. Com useMemo ()
, podemos retornar valores memoizados e evitar uma nova renderização se as dependências de uma função não tiverem mudado.
Para usar useMemo ()
em nosso código, os desenvolvedores do React têm alguns conselhos para nós :
- Você pode confiar em
useMemo ()
como uma otimização de desempenho, não como uma garantia semântica - Cada valor referenciado dentro da função também deve aparecer na matriz de dependências
Para nosso próximo exemplo, faremos algumas alterações em nosso
. O código abaixo mostra apenas as novas mudanças no
que criamos anteriormente.
//components/parent-component.js . . import {useState, useEffect, useRef, useMemo} de"react"; importar UseMemoCounts de"./use-memo-counts"; função padrão de exportação ParentComponent () { . . const [times, setTimes]=useState (0); const useMemoRef=useRef (0); const incrementUseMemoRef=()=> useMemoRef.current ++; //retire o comentário da próxima linha para testar seirá renderizar novamente a cada vez que o pai renderizar novamente. //const memoizedValue=useMemoRef.current ++; //a próxima linha garante que apenas renderize quando o valor dos tempos mudar const memoizedValue=useMemo (()=> incrementUseMemoRef (), [vezes]); . . Retorna ( . .); }setTimes (times + 1)} > Forçar renderização
Primeiro, estamos trazendo o importante gancho useMemo ()
. Também estamos trazendo o gancho useRef ()
para nos ajudar a rastrear quantas re-renderizações ocorreram em nosso componente. Em seguida, declaramos um estado times
que mais tarde atualizaremos para acionar/forçar uma nova renderização.
Posteriormente, declaramos uma variável memoizedValue
que armazena o valor retornado pelo gancho useMemo ()
. O gancho useMemo ()
chama nossa função incrementUseMemoRef
, que incrementa o valor de nosso useMemoRef.current
em um cada vez que houver uma mudança no dependências, ou seja, o valor times
muda.
Criamos então um botão que atualiza o valor de vezes
quando clicado. Clicar neste botão fará com que nosso gancho useMemo ()
seja acionado, o valor de memoizedValue
seja atualizado e nosso componente
renderizar novamente.
Para este exemplo, também renomeamos nosso componente
para
e agora leva um memoizedValue
prop.
Esta é a aparência:
//components/use-memo-counts.js function UseMemoCounts ({memoizedValue}) { Retorna (); } exportar UseMemoCounts padrão;Só vou renderizar novamente quando você clicar em Forçar renderização.
Eu agora renderizei: {memoizedValue} vez (es)
Agora, quando clicamos em qualquer um dos botões de queijo , nosso memoizedValue
não é atualizado. Mas quando clicamos no botão Forçar renderização , vemos que nosso memoizedValue
é atualizado e o componente
é renderizado novamente.
Se você comentar nossa linha memoizedValue
atual e descomentar a linha acima dela:
const memoizedValue=useMemoRef.current ++;
… você verá que o componente
será renderizado novamente cada vez que o
for renderizado.
Resumindo: as principais diferenças entre React.memo ()
e useMemo()
No exemplo acima, podemos ver as principais diferenças entre React.memo ()
e useMemo ()
:
-
React.memo ()
é um componente de ordem superior que podemos usar para envolver componentes que não queremos renderizar novamente, a menos que os adereços dentro deles mudem -
useMemo ()
é um React Hook que podemos usar para agrupar funções em um componente. Podemos usar isso para garantir que os valores dentro dessa função sejam recalculados apenas quando uma de suas dependências mudar
Embora a memoização possa parecer um truque bacana para usar em qualquer lugar, você deve usá-la apenas quando realmente precisar desses ganhos de desempenho. A memorização usa espaço de memória na máquina em que está sendo executada e, como tal, pode levar a efeitos indesejados.
E isso conclui este artigo!
Você pode acessar o código completo deste exemplo no GitHub e um exemplo ao vivo aqui .
A postagem React.memo ()
vs. useMemo ()
: Principais diferenças e casos de uso apareceram primeiro no LogRocket Blog .