O introducere în SWR: React Hooks pentru preluarea datelor de la distanță
Publicat: 2022-03-10SWR este o bibliotecă ușoară creată de Vercel (fostă ZEIT) care permite preluarea, stocarea în cache sau reîncărcarea datelor în timp real folosind React Hooks. Este construit cu React Suspense, care permite componentelor dvs. „să aștepte” ceva înainte de a putea reda, inclusiv date. SWR este livrat și cu funcții excelente, cum ar fi preluarea dependentă, concentrarea pe revalidare, recuperarea poziției de defilare și așa mai departe. Este, de asemenea, un instrument foarte puternic, deoarece este backend agnostic și are suport bun pentru TypeScript. Este un pachet care are un viitor luminos.
De ce ar trebui să-ți pese? Ar trebui să vă pese dacă ați căutat o bibliotecă care nu numai că preia date de la API-uri, ci și care să facă posibilă realizarea unor lucruri precum stocarea în cache și preluarea dependentă. Ceea ce va fi acoperit în acest tutorial va fi util atunci când construiți aplicații React cu o mulțime de părți mobile. Este de așteptat că ar fi trebuit să utilizați Axios și API-ul Fetch, deși vom compara modul în care diferă de SWR, nu vom intra în detalii despre cum vor fi implementate.
În acest ghid, vă voi prezenta React Hooks pentru preluarea datelor de la distanță prin construirea unei aplicații Pokedex care solicită date de la API-ul Pokemon. De asemenea, vom cerceta și alte funcții care vin cu SWR și vom evidenția diferențele sale în comparație cu soluțiile populare, cum ar fi API-ul Fetch și biblioteca Axios, și vă vom oferi motivele pentru care folosiți această bibliotecă și de ce ar trebui să fiți cu ochii pe SWR.
Deci, să începem prin a răspunde la o întrebare fundamentală: Ce este SWR?
Ce este SWR?
SWR este o inițializare a lui stale-while-revalidate. Este o bibliotecă React Hooks pentru preluarea datelor de la distanță. SWR funcționează în trei pași principali: în primul rând, returnează datele din cache (partea învechită), apoi trimite cererea de preluare (partea de revalidare) și în cele din urmă vine cu datele actualizate. Dar nu vă faceți griji, SWR se ocupă de toți acești pași pentru noi. Singurul lucru pe care trebuie să-l facem este să dăm cârligului useSWR
parametrii necesari pentru a face cererea.
SWR are, de asemenea, câteva caracteristici frumoase, cum ar fi:
- Back-end agnostic
- Navigare rapidă în pagină
- Revalidare la focalizare
- Interval de sondare
- Solicitați deduplicarea
- Mutație locală
- Paginare
- TypeScript gata
- Suport SSR
- Modul suspans
- React suportul nativ
- Ușoare.
Sună magic? Ei bine, SWR simplifică lucrurile și mărește cu siguranță experiența utilizatorului aplicației React. Și odată ce începem să-l implementăm în proiectul nostru, veți vedea de ce acest cârlig este la îndemână.
Este important să știți că numele pachetului este swr sau swr
și cârligul folosit pentru a obține caracteristicile SWR se numește useSWR
.
În teorie, SWR este poate ceea ce aveți nevoie pentru a îmbunătăți preluarea datelor. Cu toate acestea, avem deja două modalități excelente de a face solicitări HTTP în aplicația noastră: API-ul Fetch și biblioteca Axios.
Deci, de ce să folosiți o nouă bibliotecă pentru a prelua date? hai să încercăm să răspundem la această întrebare legitimă în secțiunea următoare.
Comparație cu Fetch și Axios
Avem deja multe modalități de a face solicitări HTTP în aplicațiile noastre React, iar două dintre cele mai populare sunt API-ul Fetch și biblioteca Axios. Ambele sunt grozave și ne permit să obținem sau să trimitem date cu ușurință. Cu toate acestea, odată terminată operația, nu ne vor ajuta să memorăm în cache sau să paginați datele, trebuie să o faceți singuri.
Axios sau Fetch vor gestiona cererea și vor returna răspunsul așteptat, nimic mai mult.
Și în comparație cu SWR, este puțin diferit, deoarece SWR-ul de sub capotă folosește API-ul Fetch pentru a solicita date de la server - este un fel de strat construit deasupra acestuia. Cu toate acestea, are câteva caracteristici frumoase, cum ar fi stocarea în cache, paginarea, recuperarea poziției de defilare, preluarea dependentă etc. și, mai exact, un anumit nivel de reactivitate din cutie pe care Axios sau Fetch nu îl au. Este un mare avantaj, deoarece deținerea unor astfel de funcții ajută la ca aplicațiile noastre React să fie rapide și ușor de utilizat și să reducă semnificativ dimensiunea codului nostru.
Și pentru a încheia, rețineți că SWR nu este același lucru cu Axios sau Fetch, chiar dacă ajută la tratarea solicitărilor HTTP. SWR este mai avansat decât ei, oferă unele îmbunătățiri pentru a menține aplicația noastră sincronizată cu back-end și, prin urmare, crește performanța aplicației noastre.
Acum știm care sunt diferențele pe care SWR are în comparație cu biblioteca Axios sau cu API-ul Fetch, este timpul să descoperim de ce folosim un astfel de instrument.
Lectură recomandată : Consumul de API-uri REST în reacție cu Fetch și Axios
De ce să folosiți SWR pentru preluarea datelor?
După cum am spus mai devreme, SWR este livrat cu câteva caracteristici utile care ajută la creșterea ușurinței de utilizare a aplicației dvs. Cu SWR, vă puteți pagina datele în cel mai scurt timp folosind useSWRPages
, puteți, de asemenea, să preluați date care depind de o altă solicitare sau să recuperați o poziție de defilare când reveniți la o anumită pagină și multe altele.
De obicei, arătăm utilizatorului un mesaj de încărcare sau un spinner în timp ce preluăm date de pe server. Și cu SWR, o puteți îmbunătăți, arătând utilizatorului datele din cache sau învechite în timp ce preluați date noi din API. Și odată ce acea operațiune este efectuată, va revalida datele pentru a afișa noua versiune. Și nu trebuie să faceți nimic, SWR va stoca în cache datele prima dată când le preluați și le va prelua automat când se face o nouă solicitare.
Până acum, vedem deja de ce utilizarea SWR peste Axios sau Fetch este mai bună, în funcție de ceea ce doriți să construiți. Dar, în multe cazuri, voi recomanda utilizarea SWR deoarece are caracteristici grozave care depășesc doar preluarea și returnarea datelor.
Acestea fiind spuse, acum putem începe să construim aplicația noastră React și să folosim biblioteca SWR pentru a prelua date de la distanță.
Deci, să începem prin a crea un nou proiect.
Configurare
După cum am spus mai devreme în introducere, vom construi o aplicație care preia date din API-ul Pokemon. Puteți folosi un alt API dacă doriți și voi, voi rămâne cu el pentru moment.
Și pentru a crea o nouă aplicație, trebuie să rulăm următoarea comandă pe terminal:
npx create-react-app react-swr
Apoi, trebuie să instalăm biblioteca SWR navigând mai întâi la folderul care deține aplicația React.
cd react-swr
Și rulați pe terminal următoarea comandă pentru a instala pachetul SWR.
yarn add swr
Sau dacă utilizați npm:
npm install swr
Acum am terminat totul, haideți să structurem proiectul după cum urmează pentru a începe să folosiți 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
După cum puteți vedea, structura folderului este simplă. Singurul lucru de observat este folderul de components
care deține fișierul Pokemon.js
. Va fi folosit mai târziu ca componentă de prezentare pentru a afișa un singur Pokemon odată ce obținem date din API.
Grozav! Odată cu acest lucru, acum putem începe să preluăm date din API folosind useSWR
.
Preluarea datelor de la distanță
Pachetul SWR are câteva caracteristici utile, așa cum am văzut mai sus. Cu toate acestea, există două moduri de a configura această bibliotecă: fie local, fie global.
O configurare locală înseamnă că de fiecare dată când creăm un fișier nou, trebuie să setăm din nou SWR pentru a putea prelua date de la distanță. Și o configurare globală ne permite să reutilizam o parte din configurația noastră în diferite fișiere, deoarece o funcție de fetcher
poate fi declarată o dată și utilizată peste tot.
Și nu vă faceți griji, le vom vedea pe ambele în acest articol, dar, deocamdată, să ne murdărim mâinile și să adăugăm un cod semnificativ în fișierul App.js
Afișarea Datelor
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
După cum puteți vedea, începem prin a importa useSWR
din biblioteca SWR. Aceasta declară adresa URL a API-ului de la care doriți să obțineți date și o funcție pentru a prelua aceste date.
Funcția fetcher
este folosită aici pentru a transforma datele în JSON. Primește datele preluate ca argument și returnează ceva.
Observați că aici, folosesc operatorul Rest ( (...args)
), deoarece nu sunt sigur de tipul și lungimea datelor primite ca parametru, prin urmare, copiez totul înainte de a-l transmite din nou ca argument la fetch
. metodă oferită de useSWR
care transformă datele în JSON și le returnează.
Acestea fiind spuse, fetcher
-ul și url
a API-ului pot fi acum transmise ca parametri la cârligul useSWR
. Cu asta, acum poate face cererea și returnează două stări: datele preluate și o stare de eroare. Și data: result
este același cu data.result
, folosim destructurarea obiectelor pentru a extrage result
din data
.
Cu valorile returnate, acum putem verifica dacă datele sunt preluate cu succes și apoi să le parcurgem în buclă. Și pentru fiecare utilizator, folosește componenta Pokemon pentru a-l afișa.
Acum avem datele și le transmitem către Componenta Pokemon, este timpul să actualizăm Pokemon.js
pentru a putea primi și afișa datele.
Crearea componentei 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> ) }
Aici, avem o componentă care primește o singură dată Pokemon de la API și o afișează. Cu toate acestea, datele primite nu conțin toate câmpurile necesare, prin urmare trebuie să facem o altă solicitare către API pentru a obține obiectul Pokemon complet.
Și după cum puteți vedea, folosim același proces pentru a prelua datele, chiar dacă de data aceasta atașăm numele Pokemonului la adresa URL.
Apropo, dacă nu sunteți familiarizat cu destructurarea, ({ pokemon })
este același lucru cu primirea elementelor de recuzită și accesarea obiectului pokemon cu props.pokemon
. Este doar o prescurtare pentru a extrage valori din obiecte sau matrice.
Cu asta în loc, dacă navigați la folderul rădăcină al proiectului și rulați pe terminal următoarea comandă:
yarn start
Sau dacă utilizați npm:
npm start
Ar trebui să vedeți că datele sunt preluate cu succes din API-ul Pokemon și afișate conform așteptărilor.
Grozav! Acum putem prelua date de la distanță cu SWR. Cu toate acestea, această configurare este una locală și poate fi puțin redundantă, deoarece puteți vedea deja că App.js
și Pokemon.js
folosesc aceeași funcție de preluare pentru a face același lucru.
Dar, din fericire, pachetul vine cu un furnizor la îndemână numit SWRConfig
, care ajută la configurarea SWR la nivel global. Este o componentă wrapper care permite componentelor copil să utilizeze configurația globală și, prin urmare, funcția fetcher.
Pentru a configura SWR la nivel global, trebuie să actualizăm fișierul index.js
, deoarece acolo este redată componenta App folosind React DOM. Dacă doriți, puteți utiliza SWRConfig
direct în fișierul App.js
Configurarea SWR la nivel global
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') )
După cum puteți vedea, începem prin a importa SWRConfig
, care este un furnizor care trebuie să încapsuleze componenta superioară sau doar o parte a aplicației dvs. React care trebuie să utilizeze funcțiile SWR. Ia drept recuzită o valoare care așteaptă un obiect de config. Puteți trece mai mult de o proprietate obiectului de configurare, aici am nevoie doar de funcția pentru a prelua date.
Acum, în loc să declarăm funcția fetcher
în fiecare fișier, o creăm aici și o transmitem ca valoare către SWRConfig
. Cu asta, acum putem prelua date la orice nivel din aplicația noastră fără a crea o altă funcție și, prin urmare, evităm redundanța.
Pe lângă asta, fetcher
este egal cu fetcher: fetcher
, este doar zahăr sintactic propus de ES6. Cu această modificare, trebuie să ne actualizăm componentele pentru a folosi configurația globală.
Utilizarea Global SWR Config
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
Acum trebuie doar să transmitem url
la useSWR
, în loc să trecem metoda url
și fetcher
. Să modificăm puțin și componenta 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> ) }
Puteți vedea deja că nu mai avem funcție de preluare, datorită configurației globale care trece funcția pentru a useSWR
sub capotă.
Acum, puteți utiliza funcția global fetcher peste tot în aplicația dvs. Singurul lucru de care are nevoie cârligul useSWR
pentru a prelua date de la distanță este adresa URL.
Cu toate acestea, putem încă îmbunătăți configurația prin crearea unui cârlig personalizat pentru a evita declararea URL-ului din nou și din nou și, în schimb, trecem ca parametru calea.
Configurare avansată prin crearea unui cârlig personalizat
Pentru a face acest lucru, trebuie să creați un fișier nou în rădăcina proiectului numit useRequest.js
(puteți să-l denumiți cum doriți) și să adăugați mai jos acest bloc de cod.
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 } }
Aici, avem o funcție care primește o cale și, opțional, un nume și o adaugă la adresa URL de bază pentru a construi adresa URL completă. Apoi, verifică dacă un parametru de nume este primit sau nu și îl gestionează în consecință.
Apoi, acea adresă URL este transmisă ca parametru cârligului useSWR
pentru a putea prelua datele de la distanță și a le returna. Și dacă nu trece nicio cale, se afișează o eroare.
Grozav! acum trebuie să modificăm puțin componentele pentru a folosi cârligul nostru personalizat.
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
Acum, în loc să folosim cârligul SWR, folosim cârligul personalizat construit deasupra acestuia și apoi trecem așa cum era de așteptat calea ca argument. Cu aceasta, totul va funcționa ca înainte, dar cu o configurație mult mai curată și flexibilă.
Să actualizăm și componenta 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> ) }
Puteți vedea deja cum cârligul nostru personalizat face lucrurile mai ușoare și mai flexibile. Aici, trebuie doar să transmitem în plus numele Pokemonului pentru a-l prelua pentru a useRequest
și se ocupă de totul pentru noi.
Sper că începeți să vă bucurați de această bibliotecă grozavă — Cu toate acestea, mai avem lucruri de descoperit, deoarece SWR oferă atât de multe funcții, iar una dintre ele este useSWRPages
, care este un cârlig pentru a pagina datele cu ușurință. Deci, să folosim acel cârlig în proiect.
Paginați datele noastre cu useSWRPages
SWR ne permite să paginam datele cu ușurință și să solicităm doar o parte din ele și, atunci când este necesar, să recăpătăm datele pentru a le afișa pentru pagina următoare.
Acum, să creăm un fișier nou în rădăcina proiectului usePagination.js
și să-l folosim ca un cârlig personalizat pentru paginare.
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 } }
După cum puteți vedea, aici începem prin a importa useSWRPages
, care este ajutorul care permite paginarea cu ușurință a datelor. Primește 4 argumente: cheia pokemon-page
solicitare care este folosită și pentru stocarea în cache, o funcție de preluare a datelor care returnează o componentă dacă datele sunt preluate cu succes și o altă funcție care preia obiectul SWR
și solicită date de la pagina următoare și o serie de dependențe.
Și odată preluate datele, funcția useSWRPages
returnează mai multe valori, dar aici avem nevoie de 4 dintre ele: pages
care sunt componenta returnată cu datele, funcția isLoadingMore
care verifică dacă datele sunt preluate în prezent, funcția loadMore
care ajută la preluare. mai multe date, iar metoda este isReachingEnd
care determină dacă mai sunt date de preluat sau nu.
Acum avem cârligul personalizat care returnează valorile necesare pentru paginarea datelor, acum putem trece la fișierul App.js
și îl putem modifica puțin.
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> ) }
Odată importat cârligul usePagination
, acum putem trece calea ca parametru și obținem înapoi valorile returnate. Și deoarece pages
sunt o componentă, nu trebuie să trecem prin buclă prin date sau ceva de genul acesta.
Apoi, folosim funcția loadMore
de pe butonul pentru a prelua mai multe date și pentru a le dezactiva dacă operația de recuperare nu este finalizată sau dacă nu există date de preluat.
Grozav! cu această modificare, acum putem naviga pe rădăcina proiectului și putem porni serverul cu această comandă pentru a previzualiza aplicația noastră.
yarn start
Sau dacă utilizați npm:
npm start
Ar trebui să vedeți că datele sunt preluate cu succes și dacă faceți clic pe butonul, datele noi vor fi preluate de SWR.
Până acum, am văzut în practică biblioteca SWR și sper că îi găsiți valoare. Cu toate acestea, are încă câteva caracteristici de oferit. Să ne aprofundăm în aceste funcționalități în secțiunea următoare.
Alte caracteristici ale SWR
Biblioteca SWR are o mulțime de lucruri la îndemână care simplifică modul în care construim aplicații React.
Revalidarea focalizării
Este o caracteristică care permite actualizarea sau revalidarea pentru a fi precisă a datelor atunci când re-focalizați o pagină sau comutați între file. Și în mod implicit, această funcționalitate este activată, dar o puteți dezactiva oricum dacă nu se potrivește nevoilor dvs. Poate fi util mai ales dacă aveți date cu actualizări la nivel înalt de frecvență.
Reluare la Interval
Biblioteca SWR permite preluarea datelor după o anumită perioadă de timp. Poate fi util atunci când datele dumneavoastră se modifică cu viteză mare sau trebuie să faceți o nouă solicitare pentru a obține o informație nouă din baza de date.
Mutația locală
Cu SWR, puteți seta o stare locală temporară care se va actualiza automat când sunt preluate date noi (revalidare). Această caracteristică intră în joc în special atunci când aveți de-a face cu o abordare offline-first, vă ajută să actualizați cu ușurință datele.
Defilați Recuperarea poziției
Această caracteristică este foarte utilă, mai ales când vine vorba de a face față listelor uriașe. Vă permite să recuperați poziția de defilare după ce vă întoarceți la pagină. Și, în orice caz, crește gradul de utilizare al aplicației dvs.
Preluare dependentă
SWR vă permite să preluați date care depind de alte date. Aceasta înseamnă că poate prelua datele A și, odată ce acea operațiune este finalizată, o folosește pentru a prelua datele B evitând în același timp cascadele. Și această caracteristică vă ajută atunci când aveți date relaționale.
Acestea fiind spuse, SWR ajută la creșterea experienței utilizatorului în orice problemă. Are mai multe funcții decât atât și, în multe cazuri, este mai bine să-l folosești peste API-ul Fetch sau biblioteca Axios.
Concluzie
Pe parcursul acestui articol, am văzut de ce SWR este o bibliotecă minunată. Permite preluarea de la distanță a datelor folosind React Hooks și ajută la simplificarea unor funcții avansate din cutie, cum ar fi paginarea, stocarea în cache a datelor, recuperarea la interval, recuperarea poziției de defilare și așa mai departe. SWR este, de asemenea, backend agnostic, ceea ce înseamnă că poate prelua date din orice tip de API-uri sau baze de date. În definitiv, SWR mărește foarte mult experiența utilizatorului aplicațiilor tale React, are un viitor strălucit și ar trebui să fii cu ochii pe el sau mai bine să-l folosești în următoarea aplicație React.
Puteți previzualiza în direct proiectul finalizat aici.
Multumesc pentru lectura!
Pasii urmatori
Puteți continua să verificați următoarele link-uri, care vă vor oferi o mai bună înțelegere dincolo de scopul acestui tutorial.
- SWR
- SWR Docs
Citiți suplimentare despre SmashingMag:
- Componente de styling în React
- Reductoare mai bune cu Immer
- Componente de ordin superior în React
- Construirea de componente React reutilizabile folosind Tailwind