"O que é memoization e como o hook `useMemo` funciona?"

À medida que sua aplicação React cresce, re-renderizações desnecessárias e cálculos caros podem diminuir o desempenho, levando a atualizações lentas da UI e aumento no uso de recursos. Isso pode ser especialmente problemático em aplicativos com gerenciamento de estado complexo, listas grandes, funções que exigem cálculos pesados e muitos componentes com um único pai. Isso gera a necessidade de otimizar seu app React para melhor desempenho, minimizando cálculos redundantes e garantindo interações mais suaves. React resolve esse problema com um processo chamado memoization, uma técnica que armazena em cache valores e funções para evitar recálculos desnecessários, para que seu app possa ser mais rápido e responsivo. Por definição, memoization é uma técnica de otimização na qual o resultado de chamadas de função caras é armazenado em cache (lembrado) com base em argumentos específicos. Quando os mesmos argumentos são fornecidos novamente, o resultado em cache é retornado em vez de recalcular a função. O processo de memoização acontece desta forma:
  • Armazene os resultados das chamadas de função junto com seus argumentos de entrada.
  • Antes de executar a função, verifique se o resultado para os argumentos atuais já existe no cache.
  • Se existir, retorne o resultado em cache em vez de executar o cálculo novamente.
  • Se não existir, calcule o resultado, armazene-o no cache e então retorne-o.
Para melhorar a experiência do desenvolvedor com memoização, o React fornece três ferramentas – React.memo (ou memo), useMemo e useCallback.  Como você pode imaginar, tanto useMemo e useCallback são hooks, mas React.memo é um wrapper de componente, um componente de ordem superior (HOC). Na próxima lição, vamos ver como o hook useCallback e React.memo funcionam. useMemo permite que você memorize valores computados enquanto useCallback faz o mesmo para referências de função. Se você está se perguntando o que são valores computados e referências de função, valores computados referem-se ao resultado da execução de uma função, enquanto referências de função são os ponteiros para funções – o objeto da função na memória. Vamos ver como usar o hook useMemo primeiro. Aqui está a sintaxe básica do hook useMemo:
const memoizedValue = useMemo(
  function () {
    return computeExpensiveValue(a, b);
  },
  [a, b]
);
Você pode ver que tudo o que é necessário é envolver o hook useMemo em torno da função. Este componente ExpensiveSquare receberá uma prop num que ele usará para calcular o quadrado:
function ExpensiveSquare({ num }) {
  function calculateSquare(n) {
    console.log("Calculating square...");
    return n * n;
  }

  const squared = calculateSquare(num);
  return (
    <p>
      Square of {num}: {squared}
    </p>
  );
}
export default ExpensiveSquare;
Aqui está o componente App onde o ExpensiveSquare está sendo usado:
import { useState, useEffect } from "react";
import ExpensiveSquare from "./components/ExpensiveSquare";

function App() {
 const [timer, setTimer] = useState(0);
 const [num, setNum] = useState(0);

 useEffect(() => {
   const interval = setInterval(() => setTimer((c) => c + 1), 1000);
   return () => clearInterval(interval);
 }, []);

 return (
   <div>
     <h1>Timer: {timer} seconds gone</h1>
     <ExpensiveSquare num={num} />
     <button onClick={() => setNum((n) => n + 1)}>Increase Number</button>
   </div>
 );
}

export default App;
O timer no useEffect, executando a cada segundo, fará com que a função calculateSquare seja executada toda vez que ele rodar, mesmo quando você não aumentar a variável de estado num. Para resolver esse problema, podemos usar o hook useMemo envolvendo a chamada da função nele e especificando a variável num como dependência:
// import the useMemo hook
import { useMemo } from "react";

function ExpensiveSquare({ num }) {
  function calculateSquare(n) {
    console.log("Calculating square...");
    return n * n;
  }

  // const squared = calculateSquare(num);
  // Wrap the function call in useMemo instead
  const squared = useMemo(() => calculateSquare(num), [num]);

  return (
    <p>
      Square of {num}: {squared}
    </p>
  );
}

export default ExpensiveSquare;
Isso garantirá que a função seja memorizada armazenando em cache o resultado. Mesmo que o componente ExpensiveSquare ainda seja re-renderizado toda vez que o estado timer do componente pai for atualizado, o cálculo da função calculateSquare só será executado novamente na renderização inicial e quando num mudar.
Este módulo não possui perguntas. Marque como concluído.