Un'introduzione a SWR: React Hooks per il recupero remoto dei dati

Pubblicato: 2022-03-10
Riepilogo rapido ↬ In questo articolo, esamineremo un nuovo modo di recuperare i dati nelle app React chiamato SWR. Questo è un insieme di hook per il recupero dei dati in remoto che semplifica le cose, come la memorizzazione nella cache, l'impaginazione e così via. Creeremo anche un'app Pokedex da zero e utilizzeremo le funzionalità SWR per ottenere dati e impaginarli.

SWR è una libreria leggera creata da Vercel (precedentemente ZEIT) che consente di recuperare, memorizzare nella cache o recuperare i dati in tempo reale utilizzando React Hooks. È costruito con React Suspense che consente ai tuoi componenti di "aspettare" qualcosa prima di poter eseguire il rendering, inclusi i dati. SWR viene fornito anche con fantastiche funzionalità come il recupero dipendente, il focus sulla riconvalida, il ripristino della posizione di scorrimento e così via. È anche uno strumento molto potente poiché è indipendente dal back-end e ha un buon supporto per TypeScript. È un pacchetto che ha un brillante futuro.

Perché dovrebbe interessarti? Dovresti preoccuparti se stai cercando una libreria che non solo recuperi i dati dalle API, ma consenta anche di eseguire operazioni come la memorizzazione nella cache e il recupero dipendente. Ciò che verrà trattato in questo tutorial sarà utile quando si creano applicazioni React con molte parti mobili. Ci si aspetta che avresti dovuto utilizzare Axios e l'API Fetch, anche se confronteremo come differiscono da SWR, non entreremo nei dettagli su come verranno implementati.

In questa guida, ti presenterò React Hooks for Remote Data Fetching creando un'app Pokedex che richiede dati dall'API Pokemon. Analizzeremo anche altre funzionalità fornite con SWR, evidenzieremo le sue differenze rispetto a soluzioni popolari come l'API Fetch e la libreria Axios e ti forniremo i motivi per cui utilizzare questa libreria e perché dovresti tenere d'occhio SWR.

Quindi, iniziamo rispondendo a una domanda fondamentale: che cos'è l'SWR?

Altro dopo il salto! Continua a leggere sotto ↓

Cos'è l'SWR?

SWR è un sigla di stantio-mentre-revalidate. È una libreria React Hooks per il recupero dei dati in remoto. SWR funziona con tre passaggi principali: in primo luogo, restituisce i dati dalla cache (la parte non aggiornata), quindi invia la richiesta di recupero (la parte di riconvalida) e infine arriva con i dati aggiornati. Ma non preoccuparti, SWR gestisce tutti questi passaggi per noi. L'unica cosa che dobbiamo fare è dare useSWR i parametri necessari per effettuare la richiesta.

SWR ha anche alcune caratteristiche interessanti come:

  • Agnostico di back-end
  • Navigazione veloce della pagina
  • Riconvalida in primo piano
  • Sondaggio a intervalli
  • Richiedi la deduplicazione
  • Mutazione locale
  • Impaginazione
  • TypeScript pronto
  • Supporto SSR
  • Modalità suspense
  • Reagire supporto nativo
  • Leggero.

Suona magico? Bene, SWR semplifica le cose e aumenta sicuramente l'esperienza utente della tua app React. E una volta che inizieremo a implementarlo nel nostro progetto, vedrai perché questo gancio è utile.

È importante sapere che il nome del pacchetto è swr o SWR e l'hook utilizzato per ottenere le funzionalità SWR è chiamato useSWR .

In teoria, l'SWR è forse ciò di cui hai bisogno per migliorare il recupero dei dati. Tuttavia, abbiamo già due ottimi modi per effettuare richieste HTTP nella nostra app: l'API Fetch e la libreria Axios.

Allora, perché usare una nuova libreria per recuperare i dati? proviamo a rispondere a questa domanda legittima nella prossima sezione.

Confronto con Fetch e Axios

Abbiamo già molti modi per effettuare richieste HTTP nelle nostre app React e due dei più popolari sono l'API Fetch e la libreria Axios. Sono entrambi fantastici e ci consentono di recuperare o inviare dati facilmente. Tuttavia, una volta eseguita l'operazione, non ci aiuteranno a memorizzare nella cache o impaginare i dati, devi farlo da soli.

Axios o Fetch gestiranno semplicemente la richiesta e restituiranno la risposta prevista, nient'altro.

E rispetto a SWR, è un po' diverso perché l'SWR nascosto utilizza l'API Fetch per richiedere dati dal server: è una specie di livello costruito su di esso. Tuttavia, ha alcune caratteristiche interessanti come la memorizzazione nella cache, l'impaginazione, il ripristino della posizione di scorrimento, il recupero dipendente, ecc. e per essere precisi un certo livello di reattività fuori dagli schemi che Axios o Fetch non hanno. È un grande vantaggio perché avere tali funzionalità aiuta a rendere le nostre app React veloci e facili da usare e a ridurre notevolmente le dimensioni del nostro codice.

E per concludere, tieni presente che SWR non è la stessa cosa di Axios o Fetch anche se aiuta a gestire le richieste HTTP. SWR è più avanzato di loro, fornisce alcuni miglioramenti per mantenere la nostra app sincronizzata con il back-end e quindi aumenta le prestazioni della nostra app.

Ora sappiamo quali sono le differenze che SWR ha rispetto alla libreria Axios o all'API Fetch, è tempo di approfondire il motivo per cui utilizzare uno strumento del genere.

Letture consigliate : Consumo di API REST in reazione a Fetch e Axios

Perché usare SWR per il recupero dei dati?

Come ho detto prima, SWR viene fornito con alcune utili funzionalità che aiutano ad aumentare facilmente l'usabilità della tua app. Con SWR, puoi impaginare i tuoi dati in pochissimo tempo usando useSWRPages , puoi anche recuperare i dati che dipendono da un'altra richiesta o recuperare una posizione di scorrimento quando torni a una determinata pagina e molto altro ancora.

Di solito, mostriamo all'utente un messaggio di caricamento o uno spinner durante il recupero dei dati dal server. E con SWR, puoi migliorarlo mostrando all'utente i dati memorizzati nella cache o non aggiornati durante il recupero di nuovi dati dall'API. E una volta eseguita l'operazione, rivaliderà i dati per mostrare la nuova versione. E non devi fare nulla, SWR memorizzerà nella cache i dati la prima volta che li recuperi e li recupererà automaticamente quando viene effettuata una nuova richiesta.

Finora, vediamo già perché usare SWR su Axios o Fetch è meglio a seconda ovviamente di ciò che miri a costruire. Ma per molti casi, raccomanderò di utilizzare SWR perché ha ottime funzionalità che vanno oltre il semplice recupero e restituzione dei dati.

Detto questo, ora possiamo iniziare a creare la nostra app React e utilizzare la libreria SWR per recuperare i dati remoti.

Quindi, iniziamo impostando un nuovo progetto.

Impostare

Come ho detto prima nell'introduzione, creeremo un'app che recupera i dati dall'API Pokemon. Puoi anche usare un'API diversa se lo desideri, per ora mi atterrò ad essa.

E per creare una nuova app, dobbiamo eseguire il seguente comando sul terminale:

 npx create-react-app react-swr

Successivamente, dobbiamo installare la libreria SWR navigando prima nella cartella che contiene l'app React.

 cd react-swr

Ed eseguire sul terminale il seguente comando per installare il pacchetto SWR.

 yarn add swr

O se stai usando npm:

 npm install swr

Ora che abbiamo impostato tutto, strutturiamo il progetto come segue per iniziare a utilizzare SWR:

 src ├── components | └── Pokemon.js ├── App.js ├── App.test.js ├── index.js ├── serviceWorker.js ├── setupTests.js ├── package.json ├── README.md ├── yarn-error.log └── yarn.lock

Come puoi vedere, la struttura delle cartelle è semplice. L'unica cosa da notare è la cartella dei components che contiene il file Pokemon.js . Verrà utilizzato in seguito come componente di presentazione per mostrare un singolo Pokemon una volta ottenuti i dati dall'API.

Grande! Con questo in atto, ora possiamo iniziare a recuperare i dati dall'API usando useSWR .

Recupero di dati remoti

Il pacchetto SWR ha alcune funzioni utili come abbiamo visto sopra. Tuttavia, ci sono due modi per configurare questa libreria: localmente o globalmente.

Una configurazione locale significa che ogni volta che creiamo un nuovo file, dobbiamo configurare nuovamente SWR per poter recuperare i dati remoti. E una configurazione globale ci consente di riutilizzare una parte della nostra configurazione all'interno di file diversi perché una funzione fetcher può essere dichiarata una volta e utilizzata ovunque.

E non preoccuparti, li vedremo entrambi in questo articolo, ma per ora sporchiamoci le mani e aggiungiamo del codice significativo nel file App.js

Visualizzazione dei dati

 import React from 'react' import useSWR from 'swr' import { Pokemon } from './components/Pokemon' const url = 'https://pokeapi.co/api/v2/pokemon' const fetcher = (...args) => fetch(...args).then((res) => res.json()) function App() { const { data: result, error } = useSWR(url, fetcher) if (error) return <h1>Something went wrong!</h1> if (!result) return <h1>Loading...</h1> return ( <main className='App'> <h1>Pokedex</h1> <div> {result.results.map((pokemon) => ( <Pokemon key={pokemon.name} pokemon={pokemon} /> ))} </div> </main> ) } export default App

Come puoi vedere, iniziamo importando useSWR dalla libreria SWR. Questo dichiara l'URL dell'API da cui vuoi ottenere i dati e una funzione per recuperare questi dati.

La funzione fetcher viene utilizzata qui per trasformare i dati in JSON. Riceve i dati recuperati come argomento e restituisce qualcosa.

Si noti che qui utilizzo l'operatore Rest ( (...args) ) poiché non sono sicuro del tipo e della lunghezza dei dati ricevuti come parametro, quindi copio tutto prima di passarlo di nuovo come argomento per il fetch metodo fornito da useSWR che trasforma i dati in JSON e li restituisce.

Detto questo, il fetcher e l' url dell'API possono ora essere passati come parametri useSWR . Con ciò, ora può effettuare la richiesta e restituisce due stati: i dati recuperati e uno stato di errore. E data: result è lo stesso di data.result , usiamo la destrutturazione degli oggetti per estrarre il result da data .

Con i valori restituiti, ora possiamo verificare se i dati sono stati recuperati correttamente e quindi scorrerli. E per ogni utente, usa il componente Pokemon per visualizzarlo.

Ora abbiamo i dati e li trasmettiamo al componente Pokemon, è ora di aggiornare Pokemon.js per poter ricevere e visualizzare i dati.

Creazione del componente Pokemon

 import React from 'react' import useSWR from 'swr' const fetcher = (...args) => fetch(...args).then((res) => res.json()) export const Pokemon = ({ pokemon }) => { const { name } = pokemon const url = 'https://pokeapi.co/api/v2/pokemon/' + name const { data, error } = useSWR(url, fetcher) if (error) return <h1>Something went wrong!</h1> if (!data) return <h1>Loading...</h1> return ( <div className='Card'> <span className='Card--id'>#{data.id}</span> <img className='Card--image' src={data.sprites.front_default} alt={name} /> <h1 className='Card--name'>{name}</h1> <span className='Card--details'> {data.types.map((poke) => poke.type.name).join(', ')} </span> </div> ) }

Qui abbiamo un componente che riceve i dati di un singolo Pokemon dall'API e lo visualizza. Tuttavia, i dati ricevuti non contengono tutti i campi necessari, quindi dobbiamo fare un'altra richiesta all'API per ottenere l'oggetto Pokemon completo.

E come puoi vedere, utilizziamo lo stesso processo per recuperare i dati anche se questa volta aggiungiamo il nome del Pokemon all'URL.

A proposito, se non hai familiarità con la destrutturazione, ({ pokemon }) equivale a ricevere oggetti di scena e accedere all'oggetto pokemon con props.pokemon . È solo una scorciatoia per estrarre valori da oggetti o array.

Con quello in atto, se navighi nella cartella principale del progetto ed esegui sul terminale il seguente comando:

 yarn start

O se stai usando npm:

 npm start

Dovresti vedere che i dati sono stati recuperati correttamente dall'API Pokemon e visualizzati come previsto.

andare a prendere
Recupero dell'illustrazione. (Grande anteprima)

Grande! Ora siamo in grado di recuperare dati remoti con SWR. Tuttavia, questa configurazione è locale e può essere un po' ridondante perché puoi già vedere che App.js e Pokemon.js usano la stessa funzione di recupero per fare la stessa cosa.

Ma fortunatamente, il pacchetto viene fornito con un comodo provider chiamato SWRConfig che aiuta a configurare SWR a livello globale. È un componente wrapper che consente ai componenti figlio di utilizzare la configurazione globale e quindi la funzione fetcher.

Per configurare SWR a livello globale, è necessario aggiornare il file index.js perché è dove viene eseguito il rendering del componente App utilizzando React DOM. Se lo desideri, puoi utilizzare SWRConfig direttamente nel file App.js

Configurazione SWR a livello globale

 import React from 'react' import ReactDOM from 'react-dom' import { SWRConfig } from 'swr' import App from './App' import './index.css' const fetcher = (...args) => fetch(...args).then((res) => res.json()) ReactDOM.render( <React.StrictMode> <SWRConfig value={{ fetcher }}> <App /> </SWRConfig> </React.StrictMode>, document.getElementById('root') )

Come puoi vedere, iniziamo importando SWRConfig che è un provider che deve avvolgere il componente superiore o solo una parte della tua app React che deve utilizzare le funzionalità SWR. Prende come prop un valore che si aspetta un oggetto di config. Puoi passare più di una proprietà all'oggetto di configurazione, qui ho solo bisogno della funzione per recuperare i dati.

Ora, invece di dichiarare la funzione fetcher in ogni file, la creiamo qui e la passiamo come valore a SWRConfig . Con ciò, ora possiamo recuperare i dati a qualsiasi livello nella nostra app senza creare un'altra funzione e quindi evitare la ridondanza.

Oltre a ciò, fetcher è uguale a fetcher: fetcher , è solo zucchero sintattico proposto da ES6. Con questa modifica, ora dobbiamo aggiornare i nostri componenti per utilizzare la configurazione globale.

Utilizzando la configurazione globale SWR

 import React from 'react' import useSWR from 'swr' import { Pokemon } from './components/Pokemon' const url = 'https://pokeapi.co/api/v2/pokemon' function App() { const { data: result, error } = useSWR(url) if (error) return <h1>Something went wrong!</h1> if (!result) return <h1>Loading...</h1> return ( <main className='App'> <h1>Pokedex</h1> <div> {result.results.map((pokemon) => ( <Pokemon key={pokemon.name} pokemon={pokemon} /> ))} </div> </main> ) } export default App

Ora dobbiamo solo passare l' url a useSWR , invece di passare l' url e il metodo fetcher . Modifichiamo un po' anche il componente Pokemon.

 import React from 'react' import useSWR from 'swr' export const Pokemon = ({ pokemon }) => { const { name } = pokemon const url = 'https://pokeapi.co/api/v2/pokemon/' + name const { data, error } = useSWR(url) if (error) return <h1>Something went wrong!</h1> if (!data) return <h1>Loading...</h1> return ( <div className='Card'> <span className='Card--id'>#{data.id}</span> <img className='Card--image' src={data.sprites.front_default} alt={name} /> <h1 className='Card--name'>{name}</h1> <span className='Card--details'> {data.types.map((poke) => poke.type.name).join(', ')} </span> </div> ) }

Puoi già vedere che non abbiamo più la funzione fetcher, grazie alla configurazione globale che passa la funzione a useSWR sotto il cofano.

Ora puoi utilizzare la funzione di recupero globale ovunque nella tua app. L'unica cosa di cui l'hook useSWR bisogno per recuperare i dati remoti è l'URL.

Tuttavia, possiamo ancora migliorare ulteriormente l'impostazione creando un hook personalizzato per evitare di dichiarare l'URL ancora e ancora e, invece, passare semplicemente come parametro il percorso.

Configurazione avanzata creando un hook personalizzato

Per fare ciò, devi creare un nuovo file nella radice del progetto chiamato useRequest.js (puoi nominarlo come vuoi) e aggiungere questo blocco di codice qui sotto.

 import useSwr from 'swr' const baseUrl = 'https://pokeapi.co/api/v2' export const useRequest = (path, name) => { if (!path) { throw new Error('Path is required') } const url = name ? baseUrl + path + '/' + name : baseUrl + path const { data, error } = useSwr(url) return { data, error } }

Qui abbiamo una funzione che riceve un percorso e, facoltativamente, un nome e lo aggiunge all'URL di base per creare l'URL completo. Successivamente, controlla se un parametro del nome viene ricevuto o meno e lo gestisce di conseguenza.

Quindi, quell'URL viene passato come parametro useSWR per poter recuperare i dati remoti e restituirli. E se non viene passato alcun percorso, genera un errore.

Grande! ora dobbiamo modificare un po' i componenti per usare il nostro hook personalizzato.

 import React from 'react' import { useRequest } from './useRequest' import './styles.css' import { Pokemon } from './components/Pokemon' function App() { const { data: result, error } = useRequest('/pokemon') if (error) return <h1>Something went wrong!</h1> if (!result) return <h1>Loading...</h1> return ( <main className='App'> <h1>Pokedex</h1> <div> {result.results.map((pokemon) => ( <Pokemon key={pokemon.name} pokemon={pokemon} /> ))} </div> </main> ) } export default App

Ora, invece di usare l'hook SWR, utilizziamo l'hook personalizzato costruito su di esso e quindi passiamo come previsto il percorso come argomento. Con quello in atto, tutto funzionerà come prima ma con una configurazione molto più pulita e flessibile.

Aggiorniamo anche il componente Pokemon.

 import React from 'react' import { useRequest } from '../useRequest' export const Pokemon = ({ pokemon }) => { const { name } = pokemon const { data, error } = useRequest('/pokemon', name) if (error) return <h1>Something went wrong!</h1> if (!data) return <h1>Loading...</h1> return ( <div className='Card'> <span className='Card--id'>#{data.id}</span> <img className='Card--image' src={data.sprites.front_default} alt={name} /> <h1 className='Card--name'>{name}</h1> <span className='Card--details'> {data.types.map((poke) => poke.type.name).join(', ')} </span> </div> ) }

Puoi già vedere come il nostro gancio personalizzato rende le cose più facili e flessibili. Qui, dobbiamo solo passare anche il nome del Pokemon da recuperare per useRequest e gestisce tutto per noi.

Spero che inizi a goderti questa fantastica libreria - Tuttavia, abbiamo ancora cose da scoprire perché SWR offre così tante funzionalità e una di queste è useSWRPages che è un gancio per impaginare facilmente i dati. Quindi, usiamo quel gancio nel progetto.

Impagina i nostri dati con useSWRPages

SWR ci consente di impaginare facilmente i dati e richiederne solo una parte e, quando necessario, recuperare i dati da mostrare per la pagina successiva.

Ora creiamo un nuovo file nella radice del progetto usePagination.js e usiamolo come hook personalizzato per l'impaginazione.

 import React from 'react' import useSWR, { useSWRPages } from 'swr' import { Pokemon } from './components/Pokemon' export const usePagination = (path) => { const { pages, isLoadingMore, loadMore, isReachingEnd } = useSWRPages( 'pokemon-page', ({ offset, withSWR }) => { const url = offset || `https://pokeapi.co/api/v2${path}` const { data: result, error } = withSWR(useSWR(url)) if (error) return <h1>Something went wrong!</h1> if (!result) return <h1>Loading...</h1> return result.results.map((pokemon) => ( <Pokemon key={pokemon.name} pokemon={pokemon} /> )) }, (SWR) => SWR.data.next, [] ) return { pages, isLoadingMore, loadMore, isReachingEnd } }

Come puoi vedere, qui iniziamo importando useSWRPages che è l'helper che consente di impaginare facilmente i dati. Riceve 4 argomenti: la chiave della pokemon-page di richiesta che viene utilizzata anche per la memorizzazione nella cache, una funzione per recuperare i dati che restituisce un componente se i dati vengono recuperati con successo e un'altra funzione che prende l'oggetto SWR e richiede i dati dal pagina successiva e una serie di dipendenze.

E una volta recuperati i dati, la funzione useSWRPages restituisce diversi valori, ma qui ne servono 4: le pages che è il componente restituito con i dati, la funzione isLoadingMore che controlla se i dati sono attualmente recuperati, la funzione loadMore che aiuta il recupero più dati e il metodo isReachingEnd che determina se ci sono ancora dati da recuperare o meno.

Ora abbiamo l'hook personalizzato che restituisce i valori necessari per impaginare i dati, ora possiamo spostarci nel file App.js e modificarlo un po'.

 import React from 'react' import { usePagination } from './usePagination' import './styles.css' export default function App() { const { pages, isLoadingMore, loadMore, isReachingEnd } = usePagination( '/pokemon' ) return ( <main className='App'> <h1>Pokedex</h1> <div>{pages}</div> <button onClick={loadMore} disabled={isLoadingMore || isReachingEnd} > Load more... </button> </main> ) }

Una volta importato l'hook usePagination , ora possiamo passare il percorso come parametro e recuperare i valori restituiti. E poiché le pages sono un componente, non abbiamo bisogno di scorrere i dati o qualcosa del genere.

Successivamente, utilizziamo la funzione loadMore sul pulsante per recuperare più dati e disabilitarla se l'operazione di recupero non è terminata o se non ci sono dati da recuperare.

Grande! con quella modifica, ora possiamo navigare sulla radice del progetto e avviare il server con questo comando per visualizzare in anteprima la nostra app.

 yarn start

O se stai usando npm:

 npm start

Dovresti vedere che i dati sono stati recuperati correttamente e se fai clic sul pulsante, i nuovi dati verranno recuperati da SWR.

Impaginazione
Impaginazione. (Grande anteprima)

Finora, abbiamo visto in pratica la libreria SWR e spero che tu stia trovando valore su di essa. Tuttavia, ha ancora alcune funzionalità da offrire. Analizziamo queste funzionalità nella prossima sezione.

Altre caratteristiche di SWR

La libreria SWR ha un sacco di cose utili che semplificano il modo in cui creiamo le app React.

Riconvalida del focus

È una funzionalità che consente di aggiornare o riconvalidare per essere precisi i dati quando si rifocalizza una pagina o si passa da una scheda all'altra. E per impostazione predefinita, questa funzionalità è abilitata, ma puoi comunque disabilitarla se non si adatta alle tue esigenze. Può essere utile soprattutto se si dispone di dati con aggiornamenti ad alta frequenza.

Recupero a intervalli

La libreria SWR consente di recuperare i dati dopo un certo periodo di tempo. Può essere utile quando i tuoi dati cambiano ad alta velocità o devi fare una nuova richiesta per ottenere una nuova informazione dal tuo database.

Mutazione locale

Con SWR, puoi impostare uno stato locale temporaneo che si aggiornerà automaticamente quando vengono recuperati nuovi dati (riconvalida). Questa funzione entra in gioco in particolare quando si ha a che fare con un approccio Offline-first, aiuta ad aggiornare facilmente i dati.

Scorri il recupero della posizione

Questa funzione è molto utile, soprattutto quando si tratta di gestire elenchi enormi. Ti permette di recuperare la posizione di scorrimento dopo essere tornato alla pagina. E in ogni caso, aumenta l'usabilità della tua app.

Recupero dipendente

SWR consente di recuperare dati che dipendono da altri dati. Ciò significa che può recuperare i dati A e, una volta eseguita l'operazione, li utilizza per recuperare i dati B evitando le cascate. E questa funzione aiuta quando si dispone di dati relazionali.

Detto questo, SWR aiuta ad aumentare l'esperienza dell'utente in qualsiasi questione. Ha più funzionalità di così e per molti casi è meglio usarlo sull'API Fetch o sulla libreria Axios.

Conclusione

In questo articolo, abbiamo visto perché SWR è una libreria fantastica. Consente il recupero remoto dei dati utilizzando React Hooks e aiuta a semplificare alcune funzionalità avanzate pronte all'uso come l'impaginazione, la memorizzazione nella cache dei dati, il recupero dell'intervallo, il ripristino della posizione di scorrimento e così via. SWR è anche indipendente dal back-end, il che significa che può recuperare dati da qualsiasi tipo di API o database. In definitiva, SWR aumenta molto l'esperienza utente delle tue app React, ha un futuro radioso e dovresti tenerlo d'occhio o meglio usarlo nella tua prossima app React.

Puoi visualizzare in anteprima il progetto finito dal vivo qui.

Grazie per aver letto!

Prossimi passi

Puoi continuare a controllare i seguenti collegamenti che ti daranno una migliore comprensione oltre lo scopo di questo tutorial.

  • SWR
  • Documenti SWR

Ulteriori letture su SmashingMag:

  • Componenti per lo styling in reazione
  • Migliori riduttori con Immer
  • Componenti di ordine superiore in reazione
  • Costruire componenti React riutilizzabili utilizzando Tailwind