From Tatooine

Performance com Memo e useMemo

March 24, 2021 • 🤔 3 min read
Tags: javascript, reactjs

No desenvolvimento com React, por vezes vemos a necessidade de melhorar a performance da aplicação, utilizando técnicas de cache de nossos componentes.

Antes de atualizar o DOM, o React primeiro renderiza o componente. Feito isso, ele compara o resultado da renderização com a anterior. Se os resultadores forem diferentes, ele o atualiza.

React Memo

É ai que entra a vantagem de utilização do React.memo(). Quando utilizamos o memo, o React memoriza o resultado do componente. Antes de o React renderizar o componente novamente, ele valida se os props (primitivos) são os mesmos, em caso positivo ele pula a renderização.

Veja abaixo um exemplo da utilização do React.memo() na prática.

import React, { memo, useState } from "react";
import ReactDOM from "react-dom";

const ComMemo = memo(props => {
  console.log("Estou renderizando com memo!");
  return <h3>{props.message}</h3>;
});

const SemMemo = props => {
  console.log("Estou renderizando sem memo!");
  return <em>{props.message}</em>;
};

const MyApp = () => {
  const [count, setCount] = useState(0);

  return (
    <div>
      <h1>React Memo</h1>
      <p>Contador: {count}</p>
      <button onClick={() => setCount(count + 1)}>Incrementar</button>
      <ComMemo message="Este componente só renderiza uma vez." />
      <SemMemo message="Este componente vai renderizar a cada mudança de estado." />
      <p>Dá uma olhada no console!</p>
    </div>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<MyApp />, rootElement);

Você pode conferir o exemplo funcionando no codesandbox, aqui.

useMemo

O useMemo é um hook que utiliza uma técnica chamada memoization. Esse hook recebe 2 parâmetros: a função que deseja memoizar e um array de variáveis que, quando alteradas, atualizam a função.

Veja abaixo um exemplo do useMemo em ação:

import React, { useState, useMemo } from "react";
import ReactDOM from "react-dom";

const Error = (props) => {
  const { active } = props;
  const message = "Mínimo de 8 caracteres";

  console.log("Componente de erro renderizando");

  return active && message;
};

const MyApp = () => {
  const [password, setPassword] = useState("");
  const [showErrors, setShowErrors] = useState(false);

  const handlePasswordChange = (event) => {
    const { value } = event.target;

    setShowErrors(value.length < 8);
    setPassword(value);
  };

  const memoizedErrors = useMemo(() => {
    return <Error active={showErrors} />;
  }, [showErrors]);

  return (
    <form>
      <h1>Cadastrar uma senha</h1>

      <input
        type="password"
        placeholder="Password"
        value={password}
        onChange={handlePasswordChange}
      />

      <button type="submit">Salvar</button>

      <p>{memoizedErrors}</p>
      <p>Dá uma olhada no log!</p>
    </form>
  );
};

ReactDOM.render(<MyApp />, document.getElementById("root"));

Você pode observar que neste exemplo o componente de erro só precisa ser renderizado novamente quando a mensagem for mostrada ou escondida.

Você pode conferir o exemplo funcionando no codesandbox, aqui.

React.memo() vs useMemo

As duas funcionalidades tem o mesmo comportamento e a diferença é uma questão de conceito.

React.memo() é um higher-order component que envolve componentes que renderizam apenas quando suas props são alteradas. Já o useMemo é um react hook que envolve funções para garantir que elas sejam renderizadas apenas quando o array de dependências for alterado.

Enfim… Existem casos em que você pode escolher utilizar um dos recursos acima. O importante é observar quando você realmente precisa resolver um GAP de performance e quando esses recursos não vão entregar muito resultado ou até mesmo impedir o correto funcionamento. Para isso, é importante colocar na prática.


Este post não seria possível sem o trabalho de pesquisa e discussão do time do capítulo de frontend do LuizaLabs.

Obrigado pela leitura! Espero que possa ter ajudado. 🚀

Até mais.