En omfattende guide til Reacts useSyncExternalStore-hook. Vi utforsker formål, implementering, fordeler og avanserte bruksområder for håndtering av ekstern tilstand.
React useSyncExternalStore: Mestre synkronisering av ekstern tilstand
useSyncExternalStore
er en React-hook introdusert i React 18 som lar deg abonnere på og lese fra eksterne datakilder på en måte som er kompatibel med concurrent rendering. Denne hooken bygger bro mellom Reacts administrerte tilstand og ekstern tilstand, som data fra tredjepartsbiblioteker, nettleser-API-er eller andre UI-rammeverk. La oss dykke dypt ned i å forstå formålet, implementeringen og fordelene.
Forstå behovet for useSyncExternalStore
Reacts innebygde tilstandshåndtering (useState
, useReducer
, Context API) fungerer eksepsjonelt bra for data som er tett koblet til Reacts komponenttre. Imidlertid må mange applikasjoner integreres med datakilder *utenfor* Reacts kontroll. Disse eksterne kildene kan inkludere:
- Tredjepartsbiblioteker for tilstandshåndtering: Integrering med biblioteker som Zustand, Jotai eller Valtio.
- Nettleser-API-er: Tilgang til data fra
localStorage
,IndexedDB
eller Network Information API. - Data hentet fra servere: Selv om biblioteker som React Query og SWR ofte foretrekkes, kan du noen ganger ønske direkte kontroll.
- Andre UI-rammeverk: I hybridapplikasjoner der React sameksisterer med andre UI-teknologier.
Å lese fra og skrive direkte til disse eksterne kildene i en React-komponent kan føre til problemer, spesielt med concurrent rendering. React kan rendre en komponent med utdatert data hvis den eksterne kilden endres mens React forbereder en ny skjerm. useSyncExternalStore
løser dette problemet ved å tilby en mekanisme for React til å trygt synkronisere med ekstern tilstand.
Hvordan useSyncExternalStore fungerer
Hooken useSyncExternalStore
aksepterer tre argumenter:
subscribe
: En funksjon som aksepterer en callback. Denne callback-en vil bli kalt hver gang den eksterne storen endres. Funksjonen skal returnere en funksjon som, når den kalles, melder seg av abonnementet på den eksterne storen.getSnapshot
: En funksjon som returnerer den nåværende verdien av den eksterne storen. React bruker denne funksjonen til å lese storens verdi under rendring.getServerSnapshot
(valgfritt): En funksjon som returnerer startverdien til den eksterne storen på serveren. Dette er kun nødvendig for server-side rendering (SSR). Hvis den ikke er oppgitt, vil React brukegetSnapshot
på serveren.
Hooken returnerer den nåværende verdien til den eksterne storen, hentet fra getSnapshot
-funksjonen. React sørger for at komponenten re-rendres hver gang verdien returnert av getSnapshot
endres, bestemt ved Object.is
-sammenligning.
Grunnleggende eksempel: Synkronisering med localStorage
La oss lage et enkelt eksempel som bruker useSyncExternalStore
for å synkronisere en verdi med localStorage
.
Value from localStorage: {localValue}
I dette eksemplet:
subscribe
: Lytter etterstorage
-hendelsen påwindow
-objektet. Denne hendelsen utløses nårlocalStorage
endres av en annen fane eller et annet vindu.getSnapshot
: Henter verdien tilmyValue
fralocalStorage
.getServerSnapshot
: Returnerer en standardverdi for server-side rendering. Denne kan hentes fra en cookie hvis brukeren tidligere har satt en verdi.MyComponent
: BrukeruseSyncExternalStore
for å abonnere på endringer ilocalStorage
og vise den nåværende verdien.
Avanserte bruksområder og betraktninger
1. Integrering med tredjepartsbiblioteker for tilstandshåndtering
useSyncExternalStore
skinner virkelig når man integrerer React-komponenter med eksterne tilstandshåndteringsbiblioteker. La oss se på et eksempel med Zustand:
Count: {count}
I dette eksemplet brukes useSyncExternalStore
til å abonnere på endringer i Zustand-storen. Legg merke til hvordan vi sender useStore.subscribe
og useStore.getState
direkte til hooken, noe som gjør integrasjonen sømløs.
2. Ytelsesoptimalisering med memoization
Siden getSnapshot
kalles ved hver rendring, er det avgjørende å sørge for at den er ytelseseffektiv. Unngå dyre beregninger i getSnapshot
. Om nødvendig, memoiser resultatet av getSnapshot
ved hjelp av useMemo
eller lignende teknikker.
Vurder dette (potensielt problematiske) eksemplet:
```javascript import { useSyncExternalStore, useMemo } from 'react'; const externalStore = { data: [...Array(10000).keys()], // Large array listeners: [], subscribe(listener) { this.listeners.push(listener); return () => { this.listeners = this.listeners.filter((l) => l !== listener); }; }, setState(newData) { this.data = newData; this.listeners.forEach((listener) => listener()); }, getState() { return this.data; }, }; function ExpensiveComponent() { const data = useSyncExternalStore( externalStore.subscribe, () => externalStore.getState().map(x => x * 2) // Expensive operation ); return (-
{data.slice(0, 10).map((item) => (
- {item} ))}
I dette eksemplet utfører getSnapshot
(den inline-funksjonen som sendes som det andre argumentet til useSyncExternalStore
) en kostbar map
-operasjon på en stor array. Denne operasjonen vil bli utført ved *hver* rendring, selv om de underliggende dataene ikke har endret seg. For å optimalisere dette, kan vi memoizere resultatet:
-
{data.slice(0, 10).map((item) => (
- {item} ))}
Nå utføres map
-operasjonen kun når externalStore.getState()
endres. Merk: du må faktisk dyp-sammenligne externalStore.getState()
eller bruke en annen strategi hvis storen muterer det samme objektet. Eksemplet er forenklet for demonstrasjonsformål.
3. Håndtering av Concurrent Rendering
Den primære fordelen med useSyncExternalStore
er dens kompatibilitet med Reacts concurrent rendering-funksjoner. Concurrent rendering lar React forberede flere versjoner av UI-et samtidig. Når den eksterne storen endres under en concurrent render, sikrer useSyncExternalStore
at React alltid bruker de mest oppdaterte dataene når endringene blir skrevet til DOM.
Uten useSyncExternalStore
kan komponenter rendre med utdatert data, noe som fører til visuelle inkonsistenser og uventet oppførsel. useSyncExternalStore
sin getSnapshot
-metode er designet for å være synkron og rask, slik at React raskt kan avgjøre om den eksterne storen har endret seg under rendring.
4. Betraktninger rundt Server-Side Rendering (SSR)
Når du bruker useSyncExternalStore
med server-side rendering, er det essensielt å oppgi getServerSnapshot
-funksjonen. Denne funksjonen brukes til å hente startverdien til den eksterne storen på serveren. Uten den vil React forsøke å bruke getSnapshot
på serveren, noe som kanskje ikke er mulig hvis den eksterne storen er avhengig av nettleserspesifikke API-er (f.eks. localStorage
).
getServerSnapshot
-funksjonen bør returnere en standardverdi eller hente data fra en server-side kilde (f.eks. cookies, database). Dette sikrer at den innledende HTML-en som rendres på serveren inneholder de korrekte dataene.
5. Feilhåndtering
Robust feilhåndtering er avgjørende, spesielt når man jobber med eksterne datakilder. Pakk inn getSnapshot
- og getServerSnapshot
-funksjonene i try...catch
-blokker for å håndtere potensielle feil. Logg feilene på en passende måte og gi tilbakefallsverdier for å forhindre at applikasjonen krasjer.
6. Custom Hooks for gjenbrukbarhet
For å fremme gjenbrukbarhet av kode, kan du innkapsle useSyncExternalStore
-logikken i en custom hook. Dette gjør det enklere å dele logikken på tvers av flere komponenter.
La oss for eksempel lage en custom hook for å få tilgang til en spesifikk nøkkel i localStorage
:
Nå kan du enkelt bruke denne hooken i hvilken som helst komponent:
```javascript import useLocalStorage from './useLocalStorage'; function MyComponent() { const [name, setName] = useLocalStorage('userName', 'Guest'); return (Hello, {name}!
setName(e.target.value)} />Beste praksis
- Hold
getSnapshot
rask: Unngå dyre beregninger igetSnapshot
-funksjonen. Memoizer resultatet om nødvendig. - Oppgi
getServerSnapshot
for SSR: Sørg for at den innledende HTML-en som rendres på serveren inneholder de korrekte dataene. - Bruk Custom Hooks: Innkapsle
useSyncExternalStore
-logikken i custom hooks for bedre gjenbrukbarhet og vedlikehold. - Håndter feil elegant: Pakk inn
getSnapshot
oggetServerSnapshot
itry...catch
-blokker. - Minimer abonnementer: Abonner kun på de delene av den eksterne storen som komponenten faktisk trenger. Dette reduserer unødvendige re-rendringer.
- Vurder alternativer: Evaluer om
useSyncExternalStore
virkelig er nødvendig. For enkle tilfeller kan andre teknikker for tilstandshåndtering være mer passende.
Alternativer til useSyncExternalStore
Selv om useSyncExternalStore
er et kraftig verktøy, er det ikke alltid den beste løsningen. Vurder disse alternativene:
- Innebygd tilstandshåndtering (
useState
,useReducer
, Context API): Hvis dataene er tett koblet til React-komponenttreet, er disse innebygde alternativene ofte tilstrekkelige. - React Query/SWR: For datahenting gir disse bibliotekene utmerkede muligheter for caching, invalidering og feilhåndtering.
- Zustand/Jotai/Valtio: Disse minimalistiske bibliotekene for tilstandshåndtering tilbyr en enkel og effektiv måte å administrere applikasjonstilstand på.
- Redux/MobX: For komplekse applikasjoner med global tilstand kan Redux eller MobX være et bedre valg (selv om de introduserer mer "boilerplate"-kode).
Valget avhenger av de spesifikke kravene til applikasjonen din.
Konklusjon
useSyncExternalStore
er et verdifullt tillegg til Reacts verktøykasse, som muliggjør sømløs integrasjon med eksterne tilstandskilder samtidig som kompatibiliteten med concurrent rendering opprettholdes. Ved å forstå formålet, implementeringen og avanserte bruksområder, kan du utnytte denne hooken til å bygge robuste og ytelseseffektive React-applikasjoner som samhandler effektivt med data fra ulike kilder.
Husk å prioritere ytelse, håndtere feil elegant og vurdere alternative løsninger før du tyr til useSyncExternalStore
. Med nøye planlegging og implementering kan denne hooken betydelig forbedre fleksibiliteten og kraften i dine React-applikasjoner.
Videre utforskning
- React-dokumentasjon for useSyncExternalStore
- Eksempler med ulike biblioteker for tilstandshåndtering (Zustand, Jotai, Valtio)
- Ytelsestester som sammenligner
useSyncExternalStore
med andre tilnærminger