Performance com Memo e useMemo
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.