Italiano

Scopri come il batching automatico di React ottimizza più aggiornamenti di stato, migliorando le prestazioni dell'applicazione e prevenendo rendering non necessari.

Batching Automatico di React: Ottimizzazione degli Aggiornamenti di Stato per le Prestazioni

Le prestazioni di React sono fondamentali per creare interfacce utente fluide e reattive. Una delle caratteristiche chiave introdotte per migliorare le prestazioni è il batching automatico. Questa tecnica di ottimizzazione raggruppa automaticamente più aggiornamenti di stato in un unico re-render, portando a significativi miglioramenti delle prestazioni. Questo è particolarmente rilevante nelle applicazioni complesse con frequenti cambiamenti di stato.

Cos'è il Batching Automatico di React?

Il batching, nel contesto di React, è il processo di raggruppamento di più aggiornamenti di stato in un unico aggiornamento. Prima di React 18, il batching veniva applicato solo agli aggiornamenti che si verificavano all'interno degli gestori di eventi di React. Gli aggiornamenti al di fuori degli gestori di eventi, come quelli all'interno di setTimeout, promise o gestori di eventi nativi, non venivano sottoposti a batching. Ciò poteva portare a re-render non necessari e colli di bottiglia nelle prestazioni.

React 18 ha introdotto il batching automatico, che estende questa ottimizzazione a tutti gli aggiornamenti di stato, indipendentemente da dove si verifichino. Ciò significa che sia che i tuoi aggiornamenti di stato avvengano all'interno di un gestore di eventi di React, di un callback setTimeout, o della risoluzione di una promise, React li raggrupperà automaticamente in un unico re-render.

Perché è Importante il Batching Automatico?

Il batching automatico offre diversi vantaggi chiave:

Come Funziona il Batching Automatico

React ottiene il batching automatico ritardando l'esecuzione degli aggiornamenti di stato fino alla fine del contesto di esecuzione corrente. Ciò consente a React di raccogliere tutti gli aggiornamenti di stato che si sono verificati durante quel contesto e di raggrupparli in un unico aggiornamento.

Considera questo esempio semplificato:

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>Conteggio 1: {count1}</p>
      <p>Conteggio 2: {count2}</p>
      <button onClick={handleClick}>Incrementa</button>
    </div>
  );
}

Prima di React 18, fare clic sul pulsante avrebbe causato due re-render: uno per setCount1 e un altro per setCount2. Con il batching automatico in React 18, entrambi gli aggiornamenti di stato vengono raggruppati, risultando in un solo re-render.

Esempi di Batching Automatico in Azione

1. Aggiornamenti Asincroni

Le operazioni asincrone, come il recupero di dati da un'API, spesso comportano l'aggiornamento dello stato al completamento dell'operazione. Il batching automatico garantisce che questi aggiornamenti di stato vengano raggruppati, anche se si verificano all'interno del callback asincrono.

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('Errore nel recupero dei dati:', error);
        setLoading(false);
      }
    }

    fetchData();
  }, []);

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

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

In questo esempio, sia setData che setLoading vengono chiamati all'interno della funzione asincrona fetchData. React raggrupperà questi aggiornamenti, risultando in un singolo re-render una volta che i dati vengono recuperati e lo stato di caricamento viene aggiornato.

2. Promise

Similmente agli aggiornamenti asincroni, le promise spesso comportano l'aggiornamento dello stato quando la promise si risolve o viene rifiutata. Il batching automatico garantisce che anche questi aggiornamenti di stato vengano raggruppati.

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 risolta!');
        } else {
          reject('Promise rifiutata!');
        }
      }, 1000);
    });

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

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

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

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

In questo caso, vengono chiamati sia setResult e setError(null) in caso di successo, sia setError e setResult(null) in caso di fallimento. Indipendentemente da ciò, il batching automatico combinerà questi in un unico re-render.

3. Gestori di Eventi Nativi

A volte, potrebbe essere necessario utilizzare gestori di eventi nativi (ad esempio, addEventListener) invece dei gestori di eventi sintetici di React. Il batching automatico funziona anche in questi casi.

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

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

    window.addEventListener('scroll', handleScroll);

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

  return <p>Posizione di Scorrimento: {scrollPosition}</p>;
}

Anche se setScrollPosition viene chiamato all'interno di un gestore di eventi nativo, React raggrupperà comunque gli aggiornamenti, prevenendo re-render eccessivi mentre l'utente scorre.

Disattivazione del Batching Automatico

In rari casi, potresti voler disattivare il batching automatico. Ad esempio, potresti voler forzare un aggiornamento sincrono per garantire che l'interfaccia utente venga aggiornata immediatamente. React fornisce l'API flushSync a questo scopo.

Nota: L'uso di flushSync dovrebbe essere fatto con parsimonia, poiché può influire negativamente sulle prestazioni. In generale, è meglio fare affidamento sul batching automatico ogni volta che è possibile.

import { flushSync } from 'react-dom';

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

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

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

In questo esempio, flushSync forza React ad aggiornare immediatamente lo stato e a re-renderizzare il componente, bypassando il batching automatico.

Best Practice per l'Ottimizzazione degli Aggiornamenti di Stato

Sebbene il batching automatico fornisca miglioramenti significativi delle prestazioni, è comunque importante seguire le best practice per ottimizzare gli aggiornamenti di stato:

Batching Automatico e Considerazioni Globali

Il batching automatico, essendo un'ottimizzazione delle prestazioni fondamentale di React, va a beneficio delle applicazioni a livello globale indipendentemente dalla posizione dell'utente, dalla velocità della rete o dal dispositivo. Tuttavia, il suo impatto può essere più evidente in scenari con connessioni Internet più lente o dispositivi meno potenti. Per un pubblico internazionale, considera questi punti:

Conclusione

Il batching automatico di React è una potente tecnica di ottimizzazione che può migliorare significativamente le prestazioni delle tue applicazioni React. Raggruppando automaticamente più aggiornamenti di stato in un unico re-render, riduce l'overhead di rendering, previene stati inconsistenti e porta a un'esperienza utente più fluida e reattiva. Comprendendo come funziona il batching automatico e seguendo le best practice per ottimizzare gli aggiornamenti di stato, puoi creare applicazioni React ad alte prestazioni che offrono un'ottima esperienza utente a livello globale. Sfruttare strumenti come React DevTools aiuta a perfezionare ulteriormente e ottimizzare i profili di prestazioni della tua applicazione in diversi contesti globali.