Vai al contenuto principale

useMemo e useCallback per migliorare le performance

Scopri come ottimizzare le prestazioni di React con useMemo e useCallback. Impara a prevenire ricalcoli inutili e migliorare l'efficienza.

useMemo e useCallback sono due hook forniti da React che aiutano a ottimizzare le prestazioni delle applicazioni. Entrambi consentono di memorizzare calcoli pesanti o funzioni per evitare ricalcoli o ricreazioni inutili durante il re-rendering dei componenti. Tuttavia, sono utilizzati in scenari leggermente diversi. Ecco un approfondimento tecnico su entrambi, con esempi in TypeScript.

useMemo

L'hook useMemo è utilizzato per memorizzare il risultato di una funzione costosa dal punto di vista computazionale. Il valore memorizzato verrà ricomputato solo se una delle sue dipendenze cambia. Questo è utile quando abbiamo operazioni costose che non vogliamo eseguire ad ogni render.

Sintassi di useMemo

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
  • Primo argomento: una funzione che ritorna il valore che si desidera memorizzare.
  • Secondo argomento: un array di dipendenze. La funzione viene rieseguita solo se una delle dipendenze cambia.

Punti chiave su useMemo

  • Utilizzato per ottimizzare le prestazioni memorizzando valori costosi da ricomputare.
  • Ricalcola il valore solo quando cambiano le dipendenze. -Previene operazioni costose ad ogni render.

Esempio di utilizzo di useMemo

import React, { useState, useMemo } from 'react';

const ExampleUseMemo: React.FC = () => {
  const [count, setCount] = useState(0);
  const [otherState, setOtherState] = useState(false);

  // Utilizziamo `useMemo` per memorizzare il risultato di un calcolo fittiziamente "costoso"
  // basato sul `count`. Questo valore verrà ricalcolato solo quando `count` cambia,
  // evitando di eseguire il calcolo ad ogni render.
  const expensiveCalculation = useMemo(() => {
    console.log("Esecuzione del calcolo costoso...");
    let result = 0;
    for (let i = 0; i < 1000000; i++) {
      result += Math.sin(count) + Math.cos(count);
    }
    return result;
  }, [count]);

  return (
    <div>
      Count: {count} - Calcolo Costoso: {expensiveCalculation}
      <button onClick={() => setCount((c) => c + 1)}>Incrementa</button>
      <button onClick={() => setOtherState(!otherState)}>Cambia Altro Stato</button>
    </div>
  );
};

useCallback

L'hook useCallback memorizza una funzione callback tra i render. È utile quando una funzione viene passata come prop a componenti figli e non si desidera che venga ricreata ad ogni render, cosa che potrebbe portare a render inutili dei componenti figli.

Sintassi di useCallback

const memoizedCallback = useCallback(() => {
  doSomething(a, b);
}, [a, b]);

Punti chiave su useCallback

  • Evita la ricreazione di funzioni callback tra i render.
  • Utile per passare callbacks a componenti ottimizzati che dipendono dall'uguaglianza delle props per evitare render inutili.
  • Aiuta a mantenere stabili le prop dei componenti figli.

Esempio di utilizzo di useCallback

import React, { useState, useCallback, useEffect } from 'react';

// Componente figlio che riceve la funzione `increment` come prop
const ChildComponent: React.FC<{ increment: () => void }> = ({ increment }) => {
  useEffect(() => {
    // Logga un messaggio ogni volta che il componente riceve una nuova istanza della funzione `increment`
    console.log('La funzione increment è cambiata.');
  }, [increment]);

  return <button onClick={increment}>Incrementa da Figlio</button>;
};

const ExampleUseCallback: React.FC = () => {
  const [count, setCount] = useState(0);
  const [otherState, setOtherState] = useState(false);

  // Utilizziamo `useCallback` per assicurarci che la funzione `increment` non venga
  // ricreata ad ogni render a meno che `count` non cambi.
  const increment = useCallback(() => {
    setCount((c) => c + 1);
  }, [count]);

  return (
    <div>
      Count: {count}
      <button onClick={increment}>Incrementa</button>
      <button onClick={() => setOtherState(!otherState)}>Cambia Altro Stato</button>
      <ChildComponent increment={increment} />
    </div>
  );
};

In questo esempio, ogni volta che modifichi otherState cliccando su "Cambia Altro Stato", il componente ExampleUseCallback viene ri-renderizzato. Tuttavia, grazie all'uso di useCallback, la funzione increment passata a ChildComponent non viene ricreata se count non cambia. Questo significa che non vedrai il log "La funzione increment è cambiata." quando modifichi otherState, indicando che increment mantiene lo stesso riferimento tra i render.

Al contrario, se rimuovi useCallback oppure cambi le sue dipendenze in modo che la funzione venga ricreata più frequentemente, noterai che il log appare ogni volta che il componente padre viene ri-renderizzato, dimostrando che senza useCallback, o con un uso improprio, la funzione increment verrebbe ricreata inutilmente, potenzialmente portando a performance peggiori in scenari con componenti figli complessi o con props che dipendono dall'uguaglianza di riferimento.

Conclusioni

L'utilizzo appropriato di useMemo e useCallback può portare a miglioramenti significativi nelle prestazioni delle applicazioni React, specialmente in quelle con una grande quantità di dati o logica computazionalmente intensiva. Tuttavia, è importante utilizzarli solo quando necessario, poiché un uso eccessivo può avere l'effetto opposto, introducendo complessità aggiuntiva e potenzialmente degradando le prestazioni a causa del costo di memorizzazione.

Unisciti a WebTea

Niente spam. Solo contenuti formativi su Software Engineering.

Ci sono due cose che non ci piacciono: lo spam e il mancato rispetto della privacy. Seleziona come vuoi restare in contatto:

Preferenze di contatto

Usiamo Mailchimp come piattaforma di marketing. Cliccando su iscriviti, accetti la nostra privacy policy e che le tue informazioni vengano trasferite a Mailchimp per l'elaborazione. Termini e Privacy. Puoi disiscriverti in qualsiasi momento.