Imparare a domare l'uso di React Callback Hook

Pubblicato: 2022-04-27

Non è un segreto che React.js sia diventato molto popolare negli ultimi anni. Ora è la libreria JavaScript preferita da molti dei giocatori più importanti di Internet, inclusi Facebook e WhatsApp.

Uno dei motivi principali della sua ascesa è stata l'introduzione degli hook nella versione 16.8. Gli hook React ti consentono di sfruttare la funzionalità di React senza scrivere componenti di classe. Ora i componenti funzionali con hook sono diventati la struttura di riferimento degli sviluppatori per lavorare con React.

In questo post del blog, approfondiremo un hook specifico, useCallback , perché tocca una parte fondamentale della programmazione funzionale nota come memorizzazione. Saprai esattamente come e quando utilizzare l'hook useCallback e sfruttare al meglio le sue capacità di miglioramento delle prestazioni.

Pronto? Immergiamoci!


Cos'è la memorizzazione?

La memorizzazione è quando una funzione complessa memorizza il suo output in modo che la prossima volta che venga chiamata con lo stesso input. È simile alla memorizzazione nella cache, ma a un livello più locale. Può saltare qualsiasi calcolo complesso e restituire l'output più velocemente poiché è già calcolato.

Ciò può avere un effetto significativo sull'allocazione della memoria e sulle prestazioni e tale sforzo è ciò che l'hook useCallback dovrebbe alleviare.

React's useCallback vs useMemo

A questo punto, vale la pena ricordare che useCallback accoppia bene con un altro hook chiamato useMemo . Ne discuteremo entrambi, ma in questo pezzo ci concentreremo su useCallback come argomento principale.

La differenza fondamentale è che useMemo restituisce un valore memorizzato, mentre useCallback restituisce una funzione memorizzata. Ciò significa che useMemo viene utilizzato per memorizzare un valore calcolato, mentre useCallback restituisce una funzione che puoi chiamare in seguito.

Questi hook ti restituiranno una versione memorizzata nella cache a meno che una delle loro dipendenze (es. stato o props) non cambi.

Diamo un'occhiata alle due funzioni in azione:

 import { useMemo, useCallback } from 'react' const values = [3, 9, 6, 4, 2, 1] // This will always return the same value, a sorted array. Once the values array changes then this will recompute. const memoizedValue = useMemo(() => values.sort(), [values]) // This will give me back a function that can be called later on. It will always return the same result unless the values array is modified. const memoizedFunction = useCallback(() => values.sort(), [values])

Il frammento di codice sopra è un esempio artificiale ma mostra la differenza tra i due callback:

  1. memoizedValue diventerà l'array [1, 2, 3, 4, 6, 9] . Finché la variabile values ​​rimane, lo sarà memoizedValue e non verrà mai ricalcolato.
  2. memoizedFunction sarà una funzione che restituirà l'array [1, 2, 3, 4, 6, 9] .

La cosa fantastica di questi due callback è che vengono memorizzati nella cache e rimangono in sospeso fino a quando l'array di dipendenze non cambia. Ciò significa che in un rendering non verranno raccolti i rifiuti.

React.js è ora la libreria JavaScript preferita da molti dei più grandi giocatori di Internet, inclusi Facebook e WhatsApp. Scopri di più in questa guida ️ Clicca per twittare

Rendering e reazione

Perché la memorizzazione è importante quando si tratta di React?

Ha a che fare con il modo in cui React rende i tuoi componenti. React utilizza un Virtual DOM archiviato in memoria per confrontare i dati e decidere cosa aggiornare.

Il DOM virtuale aiuta a reagire con le prestazioni e mantiene veloce la tua applicazione. Per impostazione predefinita, se un qualsiasi valore nel componente cambia, l'intero componente verrà riprodotto nuovamente. Questo rende React "reattivo" all'input dell'utente e consente allo schermo di aggiornarsi senza ricaricare la pagina.

Non vuoi eseguire il rendering del tuo componente perché le modifiche non influiranno su quel componente. È qui che la memorizzazione tramite useCallback e useMemo torna utile.

Quando React esegue nuovamente il rendering del tuo componente, ricrea anche le funzioni che hai dichiarato all'interno del tuo componente.

Si noti che quando si confronta l'uguaglianza di una funzione con un'altra funzione, saranno sempre false. Poiché una funzione è anche un oggetto, sarà solo uguale a se stessa:

 // these variables contain the exact same function but they are not equal const hello = () => console.log('Hello Matt') const hello2 = () => console.log('Hello Matt') hello === hello2 // false hello === hello // true

In altre parole, quando React esegue nuovamente il rendering del tuo componente, vedrà tutte le funzioni dichiarate nel tuo componente come nuove funzioni.

Questo va bene per la maggior parte del tempo e le funzioni semplici sono facili da calcolare e non influiscono sulle prestazioni. Ma le altre volte in cui non vuoi che la funzione sia vista come una nuova funzione, puoi fare affidamento su useCallback per aiutarti.

Potresti pensare: "Quando non vorrei che una funzione fosse vista come una nuova funzione?" Bene, ci sono alcuni casi in cui useCallback ha più senso:

  1. Stai passando la funzione a un altro componente anch'esso memorizzato ( useMemo )
  2. La tua funzione ha uno stato interno che deve ricordare
  3. La tua funzione è una dipendenza di un altro hook, come ad esempio useEffect

Vantaggi prestazionali di React useCallback

Quando useCallback viene utilizzato in modo appropriato, può aiutare a velocizzare l'applicazione e impedire ai componenti di eseguire nuovamente il rendering se non è necessario.

Diciamo, ad esempio, che hai un componente che recupera una grande quantità di dati ed è responsabile della visualizzazione di tali dati sotto forma di grafico o grafico, come questo:

Un grafico a barre colorato che confronta il tempo complessivo di transazione di PHP, MySQL, Reddis ed esterno (altro) in millisecondi.
Grafico a barre generato utilizzando un componente React.

Si supponga che il componente principale per il componente della visualizzazione dati venga riprodotto, ma gli oggetti di scena o lo stato modificati non influiscono su quel componente. In tal caso, probabilmente non vuoi o non devi eseguire nuovamente il rendering e recuperare tutti i dati. Evitare questo re-rendering e refetch può far risparmiare la larghezza di banda dell'utente e fornire un'esperienza utente più fluida.

Lottando con tempi di inattività e problemi con WordPress? Kinsta è la soluzione di hosting progettata per farti risparmiare tempo! Scopri le nostre caratteristiche

Svantaggi di React useCallback

Sebbene questo gancio possa aiutarti a migliorare le prestazioni, ha anche le sue insidie. Alcune cose da considerare prima di usare useCallback (e useMemo ) sono:

  • Raccolta di rifiuti: le altre funzioni che non sono già state memorizzate verranno eliminate da React per liberare memoria.
  • Allocazione della memoria: simile alla raccolta dei rifiuti, più funzioni memorizzate hai, più memoria sarà richiesta. Inoltre, ogni volta che usi questi callback, c'è un mucchio di codice all'interno di React che ha bisogno di usare ancora più memoria per fornirti l'output memorizzato nella cache.
  • Complessità del codice: quando inizi a racchiudere le funzioni in questi hook, aumenti immediatamente la complessità del tuo codice. Ora richiede una maggiore comprensione del motivo per cui questi hook vengono utilizzati e la conferma che vengono utilizzati correttamente.

Essere consapevoli delle insidie ​​di cui sopra può salvarti dal mal di testa di inciampare su di loro tu stesso. Quando si considera l'utilizzo di useCallback , assicurarsi che i vantaggi in termini di prestazioni superino gli svantaggi.

Reagire useCallback Esempio

Di seguito è riportata una semplice configurazione con un componente Pulsante e un componente Contatore. Il contatore ha due parti di stato e visualizza due componenti Button, ciascuno che aggiornerà una parte separata dello stato dei componenti del contatore.

Il componente Button contiene due props: handleClick e name. Ogni volta che viene eseguito il rendering del pulsante, verrà registrato sulla console.

 import { useCallback, useState } from 'react' const Button = ({handleClick, name}) => { console.log(`${name} rendered`) return <button onClick={handleClick}>{name}</button> } const Counter = () => { console.log('counter rendered') const [countOne, setCountOne] = useState(0) const [countTwo, setCountTwo] = useState(0) return ( <> {countOne} {countTwo} <Button handleClick={() => setCountOne(countOne + 1)} name="button1" /> <Button handleClick={() => setCountTwo(countTwo + 1)} name="button1" /> </> ) }

In questo esempio, ogni volta che fai clic su uno dei pulsanti, vedrai questo nella console:

 // counter rendered // button1 rendered // button2 rendered

Ora, se applichiamo useCallback alle nostre funzioni handleClick e avvolgiamo il nostro Button in React.memo , possiamo vedere cosa ci fornisce useCallback . React.memo è simile a useMemo e ci consente di memorizzare un componente.

 import { useCallback, useState } from 'react' const Button = React.memo(({handleClick, name}) => { console.log(`${name} rendered`) return <button onClick={handleClick}>{name}</button> }) const Counter = () => { console.log('counter rendered') const [countOne, setCountOne] = useState(0) const [countTwo, setCountTwo] = useState(0) const memoizedSetCountOne = useCallback(() => setCountOne(countOne + 1), [countOne) const memoizedSetCountTwo = useCallback(() => setCountTwo(countTwo + 1), [countTwo]) return ( <> {countOne} {countTwo} <Button handleClick={memoizedSetCountOne} name="button1" /> <Button handleClick={memoizedSetCountTwo} name="button1" /> </> ) }

Ora, quando facciamo clic su uno dei pulsanti, vedremo solo il pulsante su cui abbiamo fatto clic per accedere alla console:

 // counter rendered // button1 rendered // counter rendered // button2 rendered

Abbiamo applicato la memorizzazione al nostro componente pulsante e i valori prop passati ad esso sono visti come uguali. Le due funzioni handleClick sono memorizzate nella cache e saranno viste come la stessa funzione da React fino a quando il valore di un elemento nell'array di dipendenza non cambia (ad esempio countOne , countTwo ).

Pronto per imparare esattamente come e quando utilizzare l'hook useCallback e come sfruttare al meglio le sue capacità di miglioramento delle prestazioni? Inizia qui! Clicca per twittare

Sommario

Per quanto siano interessanti useCallback e useMemo , ricorda che hanno casi d'uso specifici: non dovresti avvolgere tutte le funzioni con questi hook. Se la funzione è computazionalmente complessa, una dipendenza di un altro hook o un prop passato a un componente memorizzato sono buoni indicatori che potresti voler raggiungere per useCallback .

Ci auguriamo che questo articolo ti abbia aiutato a comprendere questa funzionalità avanzata di React e ti abbia aiutato ad acquisire maggiore sicurezza con la programmazione funzionale lungo il percorso!