O React é um popular framework JavaScript para o desenvolvimento front-end que facilitou a vida dos desenvolvedores ao introduzir o desenvolvimento orientado a componentes.
Antes do React 16, os componentes eram geralmente definidos com Classes e tinham diferentes métodos de ciclo de vida. O React 16 promoveu a criação de componentes funcionais e introduziu os seguintes hooks:
- useEffect para lidar com o ciclo de vida do componente.
- useState para gerenciamento de estado.
Esses hooks são necessários porque as atualizações e recomputações são operações custosas, então minimizá-las melhora o desempenho da aplicação.
Recentemente, o React introduziu dois hooks, useCallback e useMemo. Assim como os hooks useEffect e useState, essas são ferramentas poderosas que podem ajudar os desenvolvedores a otimizar o desempenho de suas aplicações, reduzindo atualizações e recomputações desnecessárias.
Neste artigo, exploraremos esses hooks, analisando sua funcionalidade e examinando como eles funcionam. Também discutiremos os casos de uso apropriados para esses hooks, fornecendo exemplos práticos para ajudá-lo a entender quando e onde usá-los em seus projetos. Vamos começar!
useCallback hook
Sintaxe
const computedFn = useCallback(()=>{
doSomething(dependencies);
}, [dependencies]);No exemplo de código anterior, fazerAlgo(dependências); será retornado e armazenado na variável funcaoCalculada. Isso só ocorre quando as dependências mudam, e o useCallback fornecerá o novo valor de fazerAlgo(dependências);.
Isso é útil quando você deseja que uma função evite a renderização novamente sempre que o componente mudar.
Por exemplo, usaremos a função de debounce no campo de entrada para obter os dados apenas quando o usuário parar de escrever por um período específico.
import React, { useState } from "https://esm.sh/react@18.2.0";
import ReactDOM from "https://esm.sh/react-dom@18.2.0";
const App = () => {
const [texto, setTexto] = useState("");
const debounce = (funcao, atraso) => {
let inDebounce;
return function () {
const contexto = this;
const args = arguments;
clearTimeout(inDebounce);
inDebounce = setTimeout(() => funcao.apply(contexto, args), atraso);
};
};
const fazerChamadaApi = () => {
console.log(texto, " Fazendo uma chamada à API");
};
const chamadaApiDebounced = debounce(fazerChamadaApi, 500);
const manipuladorDeAlteracao = (e) => {
setTexto(e.target.value);
chamadaApiDebounced();
};
return (
<div>
<input type="text" onChange={manipuladorDeAlteracao} value={texto} />
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));Cada vez que o estado é atualizado, o componente é re-renderizado, e a função de debounce é novamente anexada à variável chamadaApiDebounced. Como resultado, os logs são impressos toda vez que o estado muda, e o debounce precisa ser corrigido.
Para evitar isso, podemos envolver a função de debounce dentro do useCallback, e o programa escreverá a função de debounce memorizada que mudará apenas se as dependências mudarem.
import React, { useState, useCallback } from "https://esm.sh/react@18.2.0";
import ReactDOM from "https://esm.sh/react-dom@18.2.0";
const App = () => {
const [texto, setTexto] = useState("");
const _debounce = (funcao, atraso) => {
let inDebounce;
return function () {
const contexto = this;
const args = arguments;
clearTimeout(inDebounce);
inDebounce = setTimeout(() => funcao.apply(contexto, args), atraso);
};
};
const fazerChamadaApi = (e) => {
console.log(e, "Fazendo uma chamada à API");
};
const debounce = useCallback(_debounce(fazerChamadaApi, 2000), []);
const manipuladorDeAlteracao = (e) => {
setTexto(e.target.value);
debounce(e.target.value);
};
return (
<div>
<input type="text" onChange={manipuladorDeAlteracao} value={texto} />
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));Não queremos que a função _debounce seja re-renderizada, então não estamos passando nenhuma dependência. Este código imprimirá o log somente quando o usuário parar de escrever e passarem 2000 ms. Observe no código que estamos passando o valor para debounce(e.target.value) porque ele não pode recuperar o valor do estado.
Embora pareça estar funcionando bem, não está. Se você tiver o ESLint habilitado, notará que estamos recebendo o seguinte erro de linting para o hook useCallback:
error React Hook useCallback received a function whose dependencies are unknown. Pass an inline function instead react-hooks/exhaustive-deps
Isso ocorre porque as dependências da função que useCallback está recebendo como entrada não são conhecidas, então o ESLint quer que escrevamos uma função inline.
Além disso, a função _debounce é recriada em cada re-renderização, alterando assim sua referência e anulando o propósito de armazená-la em cache.
Para corrigir isso, podemos criar um hook personalizado useDebounce e usá-lo.
import { useState, useCallback, useRef } from "react";
const useDebounce = (funcao, atraso) => {
const inDebounce = useRef();
const debounce = useCallback(
function () {
const contexto = this;
const args = arguments;
clearTimeout(inDebounce.current);
inDebounce.current = setTimeout(() => funcao.apply(contexto, args), atraso);
},
[funcao, atraso]
);
return debounce;
};
const App = () => {
const [texto, setTexto] = useState("");
const fazerChamadaApi = useCallback((e) => {
console.log(e, "Fazendo uma chamada à API");
}, []);
const debounce = useDebounce(fazerChamadaApi, 2000);
const manipuladorDeAlteracao = (e) => {
setTexto(e.target.value);
debounce(e.target.value);
};
return (
<div>
<input type="text" onChange={manipuladorDeAlteracao} value={texto} />
</div>
);
};useMemo hook
Sintaxe
const computedValue = useMemo(()=>{
doSomething();
}, [dependencies]);O useMemo funciona de forma semelhante ao useCallback, mas, em vez de retornar a função, ele retorna o valor calculado a partir da função, ou seja, a saída da função, e reexecuta a função apenas quando as dependências mudam para fornecer o novo resultado.
Por exemplo, digamos que temos um componente filho que deve ser renderizado apenas quando o texto tem um valor específico.
import React, { useState, useCallback } from "https://esm.sh/react@18.2.0";
import ReactDOM from "https://esm.sh/react-dom@18.2.0";
const ComponenteFilho = ({ texto }) => {
return <p>{texto}</p>;
};
const App = () => {
const [texto, setTexto] = useState("");
const manipuladorDeAlteracao = (e) => {
setTexto(e.target.value);
};
return (
<div>
<input type="text" onChange={manipuladorDeAlteracao} value={texto} />
<ComponenteFilho texto={texto} />
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));Se a verificação condicional fosse colocada dentro do componente filho, isso acionaria uma nova renderização toda vez que o estado do pai fosse atualizado, independentemente de nossa intenção de limitá-lo a determinados valores.
O gancho useMemo aborda esse problema. Ao empregar esse hook, o componente filho se torna memorizado, garantindo que ele só seja renderizado quando as condições especificadas em suas dependências forem atendidas.
Neste exemplo, o componente filho será renderizado exclusivamente quando o texto corresponder ao termo "syncfusion".
import React, { useState, useMemo } from "https://esm.sh/react@18.2.0";
import ReactDOM from "https://esm.sh/react-dom@18.2.0";
const ComponenteFilho = ({ texto }) => {
return <p>{texto}</p>;
};
const App = () => {
const [texto, setTexto] = useState("");
const manipuladorDeAlteracao = (e) => {
setTexto(e.target.value);
};
const componenteFilhoMemorizado = useMemo(() => <ComponenteFilho texto={texto} />, [texto === 'syncfusion'])
return (
<div>
<input type="text" onChange={manipuladorDeAlteracao} value={texto} />
{componenteFilhoMemorizado}
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));Conclusão
Obrigado por ler. Este blog explorou os dois hooks mais poderosos do React, nomeadamente useCallback e useMemo, explicando suas funções e explorando sua aplicação ótima para evitar cálculos redundantes quando os componentes React são re-renderizados.
Sugestões de cursos
Descubra o caminho para se tornar um especialista em programação web. Aprenda HTML, CSS, JavaScript e os principais frameworks nesta jornada emocionante. Com instrutores experientes e materiais práticos, você desenvolverá habilidades práticas para criar sites impressionantes e aplicativos interativos. Impulsione sua carreira na indústria de tecnologia e abra portas para oportunidades de emprego lucrativas. Garanta sua vaga hoje mesmo e inicie sua jornada para se tornar um desenvolvedor web de sucesso.
Método Para Aprender a Programar do Absoluto ZERO com Node.js, React e React Native.
As tecnologias ensinadas no curso são responsáveis por muitas vagas no mercado de trabalho.
Além da alta demanda, os salários vão de R$47.000,00 até R$197.000,00 anuais tendo empresas que possibilitam o trabalho remoto e até vagas Internacionais.
Para que você possa estar apto a preencher uma dessas vagas eu vou te apresentar o passo a passo para você se tornar um verdadeiro expert nessas tecnologias.
O curso te dará o passo a passo de como criar estruturar de um sistema do zero com Node.js, React e React Native.

