Português

Aprenda como o automatic batching do React otimiza múltiplas atualizações de estado, melhorando o desempenho e evitando re-renderizações desnecessárias.

React Automatic Batching: Otimizando Atualizações de Estado para Desempenho

O desempenho do React é crucial para criar interfaces de usuário suaves e responsivas. Um dos principais recursos introduzidos para melhorar o desempenho é o automatic batching. Essa técnica de otimização agrupa automaticamente várias atualizações de estado em uma única re-renderização, levando a ganhos significativos de desempenho. Isso é especialmente relevante em aplicativos complexos com frequentes alterações de estado.

O que é React Automatic Batching?

Batching, no contexto do React, é o processo de agrupar várias atualizações de estado em uma única atualização. Antes do React 18, o batching era aplicado apenas a atualizações que ocorriam dentro de manipuladores de eventos do React. Atualizações fora dos manipuladores de eventos, como aquelas dentro de setTimeout, promises ou manipuladores de eventos nativos, não eram agrupadas. Isso poderia levar a re-renderizações desnecessárias e gargalos de desempenho.

O React 18 introduziu o automatic batching, que estende essa otimização a todas as atualizações de estado, independentemente de onde ocorrem. Isso significa que, se suas atualizações de estado acontecerem dentro de um manipulador de eventos do React, uma função de retorno de chamada setTimeout ou uma resolução de promise, o React irá agrupá-las automaticamente em uma única re-renderização.

Por que o Automatic Batching é Importante?

O automatic batching oferece vários benefícios importantes:

Como Funciona o Automatic Batching

O React consegue o automatic batching atrasando a execução das atualizações de estado até o final do contexto de execução atual. Isso permite que o React colete todas as atualizações de estado que ocorreram durante esse contexto e as agrupe em uma única atualização.

Considere este exemplo simplificado:

function ExampleComponent() {
  const [count1, setCount1] = useState(0);
  const [count2, setCount2] = useState(0);

  function handleClick() {
    setTimeout(() => {
      setCount1(count1 + 1);
      setCount2(count2 + 1);
    }, 0);
  }

  return (
    <div>
      <p>Contagem 1: {count1}</p>
      <p>Contagem 2: {count2}</p>
      <button onClick={handleClick}>Incrementar</button>
    </div>
  );
}

Antes do React 18, clicar no botão acionaria duas re-renderizações: uma para setCount1 e outra para setCount2. Com o automatic batching no React 18, ambas as atualizações de estado são agrupadas, resultando em apenas uma re-renderização.

Exemplos de Automatic Batching em Ação

1. Atualizações Assíncronas

Operações assíncronas, como buscar dados de uma API, frequentemente envolvem a atualização do estado após a conclusão da operação. O automatic batching garante que essas atualizações de estado sejam agrupadas, mesmo que ocorram dentro do retorno de chamada assíncrono.

function DataFetchingComponent() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    async function fetchData() {
      try {
        const response = await fetch('https://api.example.com/data');
        const jsonData = await response.json();
        setData(jsonData);
        setLoading(false);
      } catch (error) {
        console.error('Erro ao buscar dados:', error);
        setLoading(false);
      }
    }

    fetchData();
  }, []);

  if (loading) {
    return <p>Carregando...</p>;
  }

  return <div>Dados: {JSON.stringify(data)}</div>;
}

Neste exemplo, setData e setLoading são chamados dentro da função assíncrona fetchData. O React irá agrupar essas atualizações, resultando em uma única re-renderização assim que os dados forem buscados e o estado de carregamento for atualizado.

2. Promises

Semelhante às atualizações assíncronas, as promises frequentemente envolvem a atualização do estado quando a promise é resolvida ou rejeitada. O automatic batching garante que essas atualizações de estado também sejam agrupadas.

function PromiseComponent() {
  const [result, setResult] = useState(null);
  const [error, setError] = useState(null);

  useEffect(() => {
    const myPromise = new Promise((resolve, reject) => {
      setTimeout(() => {
        const success = Math.random() > 0.5;
        if (success) {
          resolve('Promise resolvida!');
        } else {
          reject('Promise rejeitada!');
        }
      }, 1000);
    });

    myPromise
      .then((value) => {
        setResult(value);
        setError(null);
      })
      .catch((err) => {
        setError(err);
        setResult(null);
      });
  }, []);

  if (error) {
    return <p>Erro: {error}</p>;
  }

  if (result) {
    return <p>Resultado: {result}</p>;
  }

  return <p>Carregando...</p>;
}

Nesse caso, setResult e setError(null) são chamados em caso de sucesso ou setError e setResult(null) são chamados em caso de falha. Independentemente disso, o automatic batching combinará esses em uma única re-renderização.

3. Manipuladores de Eventos Nativos

Às vezes, pode ser necessário usar manipuladores de eventos nativos (por exemplo, addEventListener) em vez dos manipuladores de eventos sintéticos do React. O automatic batching também funciona nesses casos.

function NativeEventHandlerComponent() {
  const [scrollPosition, setScrollPosition] = useState(0);

  useEffect(() => {
    function handleScroll() {
      setScrollPosition(window.scrollY);
    }

    window.addEventListener('scroll', handleScroll);

    return () => {
      window.removeEventListener('scroll', handleScroll);
    };
  }, []);

  return <p>Posição da Rolagem: {scrollPosition}</p>;
}

Embora setScrollPosition seja chamado dentro de um manipulador de eventos nativo, o React ainda agrupará as atualizações, impedindo re-renderizações excessivas à medida que o usuário rola.

Como Desativar o Automatic Batching

Em casos raros, você pode querer desativar o automatic batching. Por exemplo, você pode querer forçar uma atualização síncrona para garantir que a interface do usuário seja atualizada imediatamente. O React fornece a API flushSync para essa finalidade.

Observação: O uso de flushSync deve ser feito com moderação, pois pode impactar negativamente o desempenho. Geralmente, é melhor confiar no automatic batching sempre que possível.

import { flushSync } from 'react-dom';

function ExampleComponent() {
  const [count, setCount] = useState(0);

  function handleClick() {
    flushSync(() => {
      setCount(count + 1);
    });
  }

  return (<button onClick={handleClick}>Incrementar</button>);
}

Neste exemplo, flushSync força o React a atualizar imediatamente o estado e re-renderizar o componente, ignorando o automatic batching.

Melhores Práticas para Otimizar as Atualizações de Estado

Embora o automatic batching forneça melhorias significativas no desempenho, ainda é importante seguir as melhores práticas para otimizar as atualizações de estado:

Automatic Batching e Considerações Globais

O automatic batching, sendo uma otimização de desempenho central do React, beneficia as aplicações globalmente, independentemente da localização do usuário, velocidade da rede ou dispositivo. No entanto, seu impacto pode ser mais notável em cenários com conexões de internet mais lentas ou dispositivos menos potentes. Para audiências internacionais, considere estes pontos:

Conclusão

O automatic batching do React é uma técnica de otimização poderosa que pode melhorar significativamente o desempenho de suas aplicações React. Ao agrupar automaticamente várias atualizações de estado em uma única re-renderização, ele reduz a sobrecarga de renderização, evita estados inconsistentes e leva a uma experiência de usuário mais suave e responsiva. Ao entender como o automatic batching funciona e seguir as melhores práticas para otimizar as atualizações de estado, você pode criar aplicações React de alto desempenho que oferecem uma ótima experiência ao usuário em todo o mundo. O uso de ferramentas como o React DevTools ajuda a refinar e otimizar ainda mais os perfis de desempenho da sua aplicação em diversos ambientes globais.

React Automatic Batching: Otimizando Atualizações de Estado para Desempenho | MLOG