Recupero di dati obsoleti durante la riconvalida con React Hook: una guida
Pubblicato: 2022-03-11Sfruttare l'estensione HTTP Cache-Control
obsoleta durante la riconvalida è una tecnica popolare. Implica l'utilizzo di risorse memorizzate nella cache (non aggiornate) se si trovano nella cache, quindi la riconvalida della cache e l'aggiornamento con una versione più recente della risorsa, se necessario. Da qui il nome stale-while-revalidate
.
Come funziona stale-while-revalidate
Quando una richiesta viene inviata per la prima volta, viene memorizzata nella cache dal browser. Quindi, quando la stessa richiesta viene inviata una seconda volta, viene prima controllata la cache. Se la cache di quella richiesta è disponibile e valida, la cache viene restituita come risposta. Quindi, la cache viene verificata per verificare che non sia aggiornata e viene aggiornata se trovata non aggiornata. La obsolescenza di una cache è determinata dal valore max-age
presente nell'intestazione Cache-Control
insieme a stale-while-revalidate
.
Ciò consente caricamenti di pagina rapidi, poiché le risorse memorizzate nella cache non si trovano più nel percorso critico. Vengono caricati all'istante. Inoltre, poiché gli sviluppatori controllano la frequenza con cui viene utilizzata e aggiornata la cache, possono impedire ai browser di mostrare agli utenti dati eccessivamente obsoleti.
I lettori potrebbero pensare che, se possono fare in modo che il server utilizzi determinate intestazioni nelle sue risposte e lasciare che il browser lo prenda da lì, allora qual è la necessità di utilizzare React e Hooks per la memorizzazione nella cache?
Si scopre che l'approccio server e browser funziona bene solo quando vogliamo memorizzare nella cache contenuto statico. Che ne dici dell'utilizzo stale-while-revalidate
per un'API dinamica? In quel caso è difficile trovare buoni valori per max-age
e stale-while-revalidate
. Spesso, invalidare la cache e recuperare una nuova risposta ogni volta che viene inviata una richiesta sarà l'opzione migliore. Ciò significa effettivamente nessuna memorizzazione nella cache. Ma con React e Hooks possiamo fare di meglio.
stale-while-revalidate
per l'API
Abbiamo notato che lo stato non stale-while-revalidate
di HTTP non funziona bene con richieste dinamiche come le chiamate API.
Anche se finiamo per usarlo, il browser restituirà la cache o la nuova risposta, non entrambe. Questo non va bene con una richiesta API poiché vorremmo risposte fresche ogni volta che viene inviata una richiesta. Tuttavia, l'attesa di nuove risposte ritarda l'usabilità significativa dell'app.
Quindi cosa facciamo?
Implementiamo un meccanismo di memorizzazione nella cache personalizzato. All'interno di ciò, troviamo un modo per restituire sia la cache che la nuova risposta. Nell'interfaccia utente, la risposta memorizzata nella cache viene sostituita con una nuova risposta quando è disponibile. Ecco come sarebbe la logica:
- Quando una richiesta viene inviata per la prima volta all'endpoint del server API, memorizzare nella cache la risposta e quindi restituirla.
- La prossima volta che si verifica la stessa richiesta API, utilizza immediatamente la risposta memorizzata nella cache.
- Quindi, invia la richiesta in modo asincrono per recuperare una nuova risposta. Quando arriva la risposta, propaga in modo asincrono le modifiche all'interfaccia utente e aggiorna la cache.
Questo approccio consente aggiornamenti dell'interfaccia utente istantanei, poiché ogni richiesta API viene memorizzata nella cache, ma anche l'eventuale correttezza nell'interfaccia utente poiché i dati di risposta aggiornati vengono visualizzati non appena sono disponibili.
In questo tutorial, vedremo un approccio passo passo su come implementarlo. Chiameremo questo approccio inattivo durante l'aggiornamento poiché l'interfaccia utente viene effettivamente aggiornata quando riceve la nuova risposta.
Preparativi: L'API
Per avviare questo tutorial, avremo prima bisogno di un'API da cui recuperiamo i dati. Fortunatamente, ci sono un sacco di finti servizi API disponibili. Per questo tutorial, useremo reqres.in.
I dati che recuperiamo sono un elenco di utenti con un parametro di query di page
. Ecco come appare il codice di recupero:
fetch("https://reqres.in/api/users?page=2") .then(res => res.json()) .then(json => { console.log(json); });
L'esecuzione di questo codice fornisce il seguente output. Eccone una versione non ripetitiva:
{ page: 2, per_page: 6, total: 12, total_pages: 2, data: [ { id: 7, email: "[email protected]", first_name: "Michael", last_name: "Lawson", avatar: "https://s3.amazonaws.com/uifaces/faces/twitter/follettkyle/128.jpg" }, // 5 more items ] }
Puoi vedere che questa è come una vera API. Abbiamo l'impaginazione nella risposta. Il parametro di query della page
è responsabile della modifica della pagina e abbiamo un totale di due pagine nel set di dati.
Utilizzo dell'API in un'app React
Vediamo come utilizziamo l'API in un'app React. Una volta che sappiamo come farlo, scopriremo la parte di memorizzazione nella cache. Useremo una classe per creare il nostro componente. Ecco il codice:
import React from "react"; import PropTypes from "prop-types"; export default class Component extends React.Component { state = { users: [] }; componentDidMount() { this.load(); } load() { fetch(`https://reqres.in/api/users?page=${this.props.page}`) .then(res => res.json()) .then(json => { this.setState({ users: json.data }); }); } componentDidUpdate(prevProps) { if (prevProps.page !== this.props.page) { this.load(); } } render() { const users = this.state.users.map(user => ( <p key={user.id}> <img src={user.avatar} alt={user.first_name} style={{ height: 24, width: 24 }} /> {user.first_name} {user.last_name} </p> )); return <div>{users}</div>; } } Component.propTypes = { page: PropTypes.number.isRequired };
Si noti che stiamo ottenendo il valore della page
tramite props
, come spesso accade nelle applicazioni del mondo reale. Inoltre, abbiamo una funzione componentDidUpdate
, che recupera i dati dell'API ogni volta che this.props.page
cambia.
A questo punto, mostra un elenco di sei utenti perché l'API restituisce sei elementi per pagina:
Aggiunta della memorizzazione nella cache non aggiornata durante l'aggiornamento
Se vogliamo aggiungere la memorizzazione nella cache non aggiornata durante l'aggiornamento a questo, dobbiamo aggiornare la nostra logica dell'app su:
- Memorizza nella cache la risposta di una richiesta in modo univoco dopo che è stata recuperata per la prima volta.
- Restituisci immediatamente la risposta memorizzata nella cache se viene trovata la cache di una richiesta. Quindi, invia la richiesta e restituisci la nuova risposta in modo asincrono. Inoltre, memorizza nella cache questa risposta per la prossima volta.
Possiamo farlo avendo un oggetto CACHE
globale che memorizza la cache in modo univoco. Per unicità, possiamo usare il valore this.props.page
come chiave nel nostro oggetto CACHE
. Quindi, codifichiamo semplicemente l'algoritmo sopra menzionato.
import apiFetch from "./apiFetch"; const CACHE = {}; export default class Component extends React.Component { state = { users: [] }; componentDidMount() { this.load(); } load() { if (CACHE[this.props.page] !== undefined) { this.setState({ users: CACHE[this.props.page] }); } apiFetch(`https://reqres.in/api/users?page=${this.props.page}`).then( json => { CACHE[this.props.page] = json.data; this.setState({ users: json.data }); } ); } componentDidUpdate(prevProps) { if (prevProps.page !== this.props.page) { this.load(); } } render() { // same render code as above } }
Poiché la cache viene restituita non appena viene trovata e poiché anche i nuovi dati di risposta vengono restituiti da setState
, ciò significa che abbiamo aggiornamenti dell'interfaccia utente senza interruzioni e nessun tempo di attesa sull'app dalla seconda richiesta in poi. Questo è perfetto, ed è in poche parole il metodo stantio durante l'aggiornamento.
La funzione apiFetch
qui non è altro che un wrapper per il fetch
in modo da poter vedere il vantaggio della memorizzazione nella cache in tempo reale. Lo fa aggiungendo un utente casuale all'elenco di users
restituiti dalla richiesta API. Aggiunge anche un ritardo casuale ad esso:
export default async function apiFetch(...args) { await delay(Math.ceil(400 + Math.random() * 300)); const res = await fetch(...args); const json = await res.json(); json.data.push(getFakeUser()); return json; } function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }
La funzione getFakeUser()
qui è responsabile della creazione di un oggetto utente falso.
Con queste modifiche, la nostra API è più reale di prima.
- Ha un ritardo casuale nella risposta.
- Restituisce dati leggermente diversi per le stesse richieste.
Detto questo, quando cambiamo la page
prop passata al Component
dal nostro componente principale, possiamo vedere la memorizzazione nella cache dell'API in azione. Prova a fare clic sul pulsante Attiva /disattiva una volta ogni pochi secondi in questo CodeSandbox e dovresti vedere un comportamento come questo:
Se guardi da vicino, accadono alcune cose.
- Quando l'app si avvia e si trova nel suo stato predefinito, viene visualizzato un elenco di sette utenti. Prendere nota dell'ultimo utente nell'elenco poiché è l'utente che verrà modificato casualmente la prossima volta che questa richiesta verrà inviata.
- Quando si fa clic su Attiva/disattiva per la prima volta, si attende un breve lasso di tempo (400-700 ms) e quindi si aggiorna l'elenco alla pagina successiva.
- Ora siamo alla seconda pagina. Ancora una volta prendi nota dell'ultimo utente nell'elenco.
- Ora facciamo di nuovo clic su Attiva/disattiva e l'app tornerà alla prima pagina. Si noti che ora l'ultima voce è sempre lo stesso utente annotato nel passaggio 1, quindi in seguito cambia nel nuovo utente (casuale). Questo perché, inizialmente, veniva mostrata la cache, quindi è stata attivata la risposta effettiva.
- Facciamo di nuovo clic su Attiva/disattiva. Succede lo stesso fenomeno. La risposta memorizzata nella cache dell'ultima volta viene caricata istantaneamente, quindi vengono recuperati nuovi dati e quindi vediamo l'ultimo aggiornamento della voce da quanto annotato nel passaggio 3.
Questo è tutto, la memorizzazione nella cache obsoleta durante l'aggiornamento che stavamo cercando. Ma questo approccio soffre di un problema di duplicazione del codice. Vediamo come va se abbiamo un altro componente di recupero dati con memorizzazione nella cache. Questo componente mostra gli articoli in modo diverso dal nostro primo componente.
Aggiunta di stantio durante l'aggiornamento a un altro componente
Possiamo farlo semplicemente copiando la logica dal primo componente. Il nostro secondo componente mostra un elenco di gatti:
const CACHE = {}; export default class Component2 extends React.Component { state = { cats: [] }; componentDidMount() { this.load(); } load() { if (CACHE[this.props.page] !== undefined) { this.setState({ cats: CACHE[this.props.page] }); } apiFetch(`https://reqres.in/api/cats?page=${this.props.page}`).then( json => { CACHE[this.props.page] = json.data; this.setState({ cats: json.data }); } ); } componentDidUpdate(prevProps) { if (prevProps.page !== this.props.page) { this.load(); } } render() { const cats = this.state.cats.map(cat => ( <p key={cat.id} style={{ background: cat.color, padding: "4px", width: 240 }} > {cat.name} (born {cat.year}) </p> )); return <div>{cats}</div>; } }
Come puoi vedere, la logica del componente coinvolta qui è praticamente la stessa del primo componente. L'unica differenza è nell'endpoint richiesto e che mostra gli elementi dell'elenco in modo diverso.
Ora mostriamo entrambi questi componenti fianco a fianco. Puoi vedere che si comportano in modo simile:
Per ottenere questo risultato, abbiamo dovuto fare molta duplicazione del codice. Se avessimo più componenti come questo, dupliremmo troppo codice.
Per risolverlo in modo non duplicato, possiamo avere un Componente di ordine superiore per recuperare e memorizzare nella cache i dati e trasmetterli come oggetti di scena. Non è l'ideale ma funzionerà. Ma se dovessimo fare più richieste in un singolo componente, avere più componenti di ordine superiore diventerebbe brutto molto rapidamente.
Poi, abbiamo il pattern render props, che è probabilmente il modo migliore per farlo nei componenti di classe. Funziona perfettamente, ma poi, di nuovo, è incline all'"inferno avvolgente" e a volte ci richiede di vincolare il contesto attuale. Questa non è una grande esperienza per gli sviluppatori e può portare a frustrazione e bug.

È qui che React Hooks salva la situazione. Ci consentono di racchiudere la logica dei componenti in un contenitore riutilizzabile in modo da poterla utilizzare in più punti. I React Hook sono stati introdotti in React 16.8 e funzionano solo con i componenti delle funzioni. Prima di arrivare al controllo della cache di React, in particolare alla memorizzazione nella cache del contenuto con Hooks, vediamo innanzitutto come eseguiamo il semplice recupero dei dati nei componenti delle funzioni.
Recupero dati API nei componenti di funzione
Per recuperare i dati API nei componenti delle funzioni, utilizziamo useState
e useEffect
.
useState
è analogo a state
e setState
dei componenti della classe. Usiamo questo hook per avere contenitori atomici di stato all'interno di un componente di funzione.
useEffect
è un hook del ciclo di vita e puoi pensarlo come una combinazione di componentDidMount
, componentDidUpdate
e componentWillUnmount
. Il secondo parametro passato a useEffect
è chiamato array di dipendenza. Quando l'array di dipendenze cambia, il callback passato come primo argomento a useEffect
viene eseguito di nuovo.
Ecco come utilizzeremo questi hook per implementare il recupero dei dati:
import React, { useState, useEffect } from "react"; export default function Component({ page }) { const [users, setUsers] = useState([]); useEffect(() => { fetch(`https://reqres.in/api/users?page=${page}`) .then(res => res.json()) .then(json => { setUsers(json.data); }); }, [page]); const usersDOM = users.map(user => ( <p key={user.id}> <img src={user.avatar} alt={user.first_name} style={{ height: 24, width: 24 }} /> {user.first_name} {user.last_name} </p> )); return <div>{usersDOM}</div>; }
Specificando page
come dipendenza da useEffect
, indichiamo a React di eseguire il nostro callback useEffect ogni volta che la page
viene modificata. Questo è proprio come componentDidUpdate
. Inoltre, useEffect
viene sempre eseguito la prima volta, quindi funziona anche come componentDidMount
.
Inattivo durante l'aggiornamento nei componenti della funzione
Sappiamo che useEffect
è simile ai metodi del ciclo di vita dei componenti. Quindi possiamo modificare la funzione di callback passata ad essa per creare la memorizzazione nella cache non aggiornata durante l'aggiornamento che avevamo nei componenti della classe. Tutto rimane lo stesso tranne il gancio useEffect
.
const CACHE = {}; export default function Component({ page }) { const [users, setUsers] = useState([]); useEffect(() => { if (CACHE[page] !== undefined) { setUsers(CACHE[page]); } apiFetch(`https://reqres.in/api/users?page=${page}`).then(json => { CACHE[page] = json.data; setUsers(json.data); }); }, [page]); // ... create usersDOM from users return <div>{usersDOM}</div>; }
Pertanto, abbiamo una cache non aggiornata durante l'aggiornamento che funziona in un componente di funzione.
Possiamo fare lo stesso per il secondo componente, ovvero convertirlo in funzione e implementare la memorizzazione nella cache non aggiornata durante l'aggiornamento. Il risultato sarà identico a quello che abbiamo avuto in classe.
Ma non è meglio dei componenti di classe, vero? Vediamo quindi come possiamo utilizzare la potenza di un hook personalizzato per creare una logica modulare di stantio durante l'aggiornamento che possiamo utilizzare su più componenti.
Un gancio personalizzato per l'aggiornamento durante l'aggiornamento
Innanzitutto, restringiamo la logica che vogliamo spostare in un hook personalizzato. Se guardi il codice precedente, sai che è la parte useState
e useEffect
. Nello specifico, questa è la logica che vogliamo modularizzare.
const [users, setUsers] = useState([]); useEffect(() => { if (CACHE[page] !== undefined) { setUsers(CACHE[page]); } apiFetch(`https://reqres.in/api/users?page=${page}`).then(json => { CACHE[page] = json.data; setUsers(json.data); }); }, [page]);
Dal momento che dobbiamo renderlo generico, dovremo rendere dinamico l'URL. Quindi dobbiamo avere l' url
come argomento. Dovremo aggiornare anche la logica di memorizzazione nella cache, poiché più richieste possono avere lo stesso valore di page
. Fortunatamente, quando la page
è inclusa nell'URL dell'endpoint, produce un valore univoco per ogni richiesta univoca. Quindi possiamo semplicemente utilizzare l'intero URL come chiave per la memorizzazione nella cache:
const [data, setData] = useState([]); useEffect(() => { if (CACHE[url] !== undefined) { setData(CACHE[url]); } apiFetch(url).then(json => { CACHE[url] = json.data; setData(json.data); }); }, [url]);
Questo è praticamente tutto. Dopo averlo avvolto all'interno di una funzione, avremo il nostro hook personalizzato. Dai un'occhiata qui sotto.
const CACHE = {}; export default function useStaleRefresh(url, defaultValue = []) { const [data, setData] = useState(defaultValue); useEffect(() => { // cacheID is how a cache is identified against a unique request const cacheID = url; // look in cache and set response if present if (CACHE[cacheID] !== undefined) { setData(CACHE[cacheID]); } // fetch new data apiFetch(url).then(newData => { CACHE[cacheID] = newData.data; setData(newData.data); }); }, [url]); return data; }
Si noti che abbiamo aggiunto un altro argomento chiamato defaultValue
. Il valore predefinito di una chiamata API può essere diverso se si utilizza questo hook in più componenti. Ecco perché l'abbiamo reso personalizzabile.
Lo stesso può essere fatto per la chiave data
nell'oggetto newData
. Se il tuo hook personalizzato restituisce una varietà di dati, potresti voler semplicemente restituire newData
e non newData.data
e gestire quell'attraversamento sul lato del componente.
Ora che abbiamo il nostro hook personalizzato, che fa il pesante lavoro di memorizzazione nella cache non aggiornata durante l'aggiornamento, ecco come lo colleghiamo ai nostri componenti. Nota l'enorme quantità di codice che siamo stati in grado di ridurre. Il nostro intero componente ora è solo tre affermazioni. Questa è una grande vittoria.
import useStaleRefresh from "./useStaleRefresh"; export default function Component({ page }) { const users = useStaleRefresh(`https://reqres.in/api/users?page=${page}`, []); const usersDOM = users.map(user => ( <p key={user.id}> <img src={user.avatar} alt={user.first_name} style={{ height: 24, width: 24 }} /> {user.first_name} {user.last_name} </p> )); return <div>{usersDOM}</div>; }
Possiamo fare lo stesso per il secondo componente. Sembrerà così:
export default function Component2({ page }) { const cats = useStaleRefresh(`https://reqres.in/api/cats?page=${page}`, []); // ... create catsDOM from cats return <div>{catsDOM}</div>; }
È facile vedere quanto codice boilerplate possiamo salvare se utilizziamo questo hook. Anche il codice sembra migliore. Se vuoi vedere l'intera app in azione, vai su questo CodeSandbox.
Aggiunta di un indicatore di caricamento per useStaleRefresh
Ora che abbiamo le basi sul punto, possiamo aggiungere più funzionalità al nostro hook personalizzato. Ad esempio, possiamo aggiungere un valore isLoading
che è true ogni volta che viene inviata una richiesta univoca e nel frattempo non abbiamo alcuna cache da mostrare.
Lo facciamo avendo uno stato separato per isLoading
e impostandolo in base allo stato dell'hook. Cioè, quando non è disponibile alcun contenuto web memorizzato nella cache, lo impostiamo su true
, altrimenti lo impostiamo su false
.
Ecco il gancio aggiornato:
export default function useStaleRefresh(url, defaultValue = []) { const [data, setData] = useState(defaultValue); const [isLoading, setLoading] = useState(true); useEffect(() => { // cacheID is how a cache is identified against a unique request const cacheID = url; // look in cache and set response if present if (CACHE[cacheID] !== undefined) { setData(CACHE[cacheID]); setLoading(false); } else { // else make sure loading set to true setLoading(true); } // fetch new data apiFetch(url).then(newData => { CACHE[cacheID] = newData.data; setData(newData.data); setLoading(false); }); }, [url]); return [data, isLoading]; }
Ora possiamo utilizzare il nuovo valore isLoading
nei nostri componenti.
export default function Component({ page }) { const [users, isLoading] = useStaleRefresh( `https://reqres.in/api/users?page=${page}`, [] ); if (isLoading) { return <div>Loading</div>; } // ... create usersDOM from users return <div>{usersDOM}</div>; }
Si noti che fatto ciò, viene visualizzato il testo "Caricamento in corso" quando una richiesta univoca viene inviata per la prima volta e non è presente alcuna cache.
Rendere useStaleRefresh
Supporta qualsiasi funzione async
Possiamo rendere il nostro hook personalizzato ancora più potente facendo in modo che supporti qualsiasi funzione async
anziché solo GET
richieste di rete. L'idea di base alla base rimarrà la stessa.
- Nell'hook, chiami una funzione asincrona che restituisce un valore dopo un po' di tempo.
- Ogni chiamata univoca a una funzione asincrona viene memorizzata correttamente nella cache.
Una semplice concatenazione di function.name
e arguments
funzionerà come chiave cache per il nostro caso d'uso. Usandolo, ecco come apparirà il nostro gancio:
import { useState, useEffect, useRef } from "react"; import isEqual from "lodash/isEqual"; const CACHE = {}; export default function useStaleRefresh(fn, args, defaultValue = []) { const prevArgs = useRef(null); const [data, setData] = useState(defaultValue); const [isLoading, setLoading] = useState(true); useEffect(() => { // args is an object so deep compare to rule out false changes if (isEqual(args, prevArgs.current)) { return; } // cacheID is how a cache is identified against a unique request const cacheID = hashArgs(fn.name, ...args); // look in cache and set response if present if (CACHE[cacheID] !== undefined) { setData(CACHE[cacheID]); setLoading(false); } else { // else make sure loading set to true setLoading(true); } // fetch new data fn(...args).then(newData => { CACHE[cacheID] = newData; setData(newData); setLoading(false); }); }, [args, fn]); useEffect(() => { prevArgs.current = args; }); return [data, isLoading]; } function hashArgs(...args) { return args.reduce((acc, arg) => stringify(arg) + ":" + acc, ""); } function stringify(val) { return typeof val === "object" ? JSON.stringify(val) : String(val); }
Come puoi vedere, stiamo usando una combinazione del nome della funzione e dei suoi argomenti stringati per identificare in modo univoco una chiamata di funzione e quindi memorizzarla nella cache. Funziona per la nostra semplice app, ma questo algoritmo è soggetto a collisioni e confronti lenti. (Con argomenti non serializzabili, non funzionerà affatto.) Quindi, per le app del mondo reale, un algoritmo di hashing corretto è più appropriato.
Un'altra cosa da notare qui è l'uso di useRef
. useRef
viene utilizzato per rendere persistenti i dati durante l'intero ciclo di vita del componente di inclusione. Poiché args
è un array, che è un oggetto in JavaScript, ogni nuovo rendering del componente che utilizza l'hook provoca la modifica del puntatore di riferimento args
. Ma args
fa parte dell'elenco delle dipendenze nel nostro primo useEffect
. Quindi la modifica degli argomenti può useEffect
args
quando non è cambiato nulla. Per contrastare ciò, eseguiamo un confronto approfondito tra gli argomenti vecchi e quelli attuali usando args
e lasciamo che il callback useEffect
eseguito solo se gli args
sono effettivamente cambiati.
Ora possiamo usare questo nuovo hook useStaleRefresh
come segue. Notare la modifica di defaultValue
qui. Poiché si tratta di un hook generico, non ci affidiamo al nostro hook per restituire la chiave data
nell'oggetto di risposta.
export default function Component({ page }) { const [users, isLoading] = useStaleRefresh( apiFetch, [`https://reqres.in/api/users?page=${page}`], { data: [] } ); if (isLoading) { return <div>Loading</div>; } const usersDOM = users.data.map(user => ( <p key={user.id}> <img src={user.avatar} alt={user.first_name} style={{ height: 24, width: 24 }} /> {user.first_name} {user.last_name} </p> )); return <div>{usersDOM}</div>; }
Puoi trovare l'intero codice in questo CodeSandbox.
Non far aspettare gli utenti: usa efficacemente il contenuto della cache con gli hook di reazione e di aggiornamento non aggiornati
L'hook useStaleRefresh
che abbiamo creato in questo articolo è un proof of concept che mostra cosa è possibile fare con React Hooks. Prova a giocare con il codice e vedi se riesci a inserirlo nella tua applicazione.
In alternativa, puoi anche provare a sfruttare lo stato di aggiornamento durante l'aggiornamento tramite una libreria open source popolare e ben mantenuta come swr o react-query. Entrambe sono potenti librerie e supportano una serie di funzionalità che aiutano con le richieste API.
React Hooks è un punto di svolta. Ci consentono di condividere la logica dei componenti in modo elegante. Ciò non era possibile prima perché lo stato del componente, i metodi del ciclo di vita e il rendering erano tutti impacchettati in un'unica entità: i componenti della classe. Ora, possiamo avere moduli diversi per tutti loro. Questo è ottimo per la componibilità e la scrittura di codice migliore. Sto usando componenti di funzione e hook per tutto il nuovo codice React che scrivo e lo consiglio vivamente a tutti gli sviluppatori React.