Frigjør kraften i gjenbrukbar logikk i React-applikasjonene dine med egendefinerte hooks. Lær hvordan du lager og utnytter egendefinerte hooks for renere og mer vedlikeholdbar kode.
Egendefinerte Hooks: Gjenbrukbare logikkmønstre i React
React Hooks revolusjonerte måten vi skriver React-komponenter på ved å introdusere tilstand- og livssyklusfunksjoner til funksjonelle komponenter. Blant de mange fordelene de tilbyr, skiller egendefinerte hooks seg ut som en kraftig mekanisme for å trekke ut og gjenbruke logikk på tvers av flere komponenter. Dette blogginnlegget vil dykke dypt inn i verdenen av egendefinerte hooks, og utforske deres fordeler, hvordan de lages og brukes med praktiske eksempler.
Hva er egendefinerte Hooks?
I bunn og grunn er en egendefinert hook en JavaScript-funksjon som starter med ordet "use" og kan kalle andre hooks. De lar deg trekke ut komponentlogikk i gjenbrukbare funksjoner. Dette er en kraftig måte å dele tilstandsbasert logikk, bivirkninger eller annen kompleks atferd mellom komponenter uten å ty til render props, higher-order components eller andre komplekse mønstre.
Nøkkelegenskaper for egendefinerte Hooks:
- Navnekonvensjon: Egendefinerte hooks må starte med ordet "use". Dette signaliserer til React at funksjonen inneholder hooks og bør følge reglene for hooks.
- Gjenbrukbarhet: Hovedformålet er å innkapsle gjenbrukbar logikk, noe som gjør det enkelt å dele funksjonalitet mellom komponenter.
- Tilstandsbasert logikk: Egendefinerte hooks kan håndtere sin egen tilstand ved hjelp av
useState
-hooken, noe som lar dem innkapsle kompleks tilstandsbasert atferd. - Bivirkninger: De kan også utføre bivirkninger ved hjelp av
useEffect
-hooken, noe som muliggjør integrasjon med eksterne API-er, datahenting og mer. - Komponerbare: Egendefinerte hooks kan kalle andre hooks, noe som lar deg bygge kompleks logikk ved å komponere mindre, mer fokuserte hooks.
Fordeler med å bruke egendefinerte Hooks
Egendefinerte hooks tilbyr flere betydelige fordeler i React-utvikling:
- Gjenbruk av kode: Den mest åpenbare fordelen er muligheten til å gjenbruke logikk på tvers av flere komponenter. Dette reduserer kodeduplisering og fremmer en mer DRY (Don't Repeat Yourself) kodebase.
- Forbedret lesbarhet: Ved å trekke ut kompleks logikk i separate egendefinerte hooks, blir komponentene dine renere og enklere å forstå. Kjernekomponentlogikken forblir fokusert på å rendre brukergrensesnittet.
- Forbedret vedlikeholdbarhet: Når logikk er innkapslet i egendefinerte hooks, kan endringer og feilrettinger gjøres på ett enkelt sted, noe som reduserer risikoen for å introdusere feil i flere komponenter.
- Testbarhet: Egendefinerte hooks kan enkelt testes isolert, noe som sikrer at den gjenbrukbare logikken fungerer korrekt uavhengig av komponentene som bruker dem.
- Forenklede komponenter: Egendefinerte hooks bidrar til å rydde opp i komponenter, noe som gjør dem mindre ordrike og mer fokuserte på sitt primære formål.
Å lage din første egendefinerte Hook
La oss illustrere hvordan man lager en egendefinert hook med et praktisk eksempel: en hook som sporer vindusstørrelsen.
Eksempel: useWindowSize
Denne hooken vil returnere den nåværende bredden og høyden på nettleservinduet. Den vil også oppdatere disse verdiene når vinduet endrer størrelse.
import { useState, useEffect } from 'react';
function useWindowSize() {
const [windowSize, setWindowSize] = useState({
width: window.innerWidth,
height: window.innerHeight,
});
useEffect(() => {
function handleResize() {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
});
}
window.addEventListener('resize', handleResize);
// Fjern hendelseslytter ved opprydding
return () => window.removeEventListener('resize', handleResize);
}, []); // Tomt array sikrer at effekten kun kjøres ved montering
return windowSize;
}
export default useWindowSize;
Forklaring:
- Importer nødvendige Hooks: Vi importerer
useState
oguseEffect
fra React. - Definer hooken: Vi lager en funksjon kalt
useWindowSize
, som følger navnekonvensjonen. - Initialiser tilstand: Vi bruker
useState
for å initialiserewindowSize
-tilstanden med den opprinnelige bredden og høyden på vinduet. - Sett opp hendelseslytter: Vi bruker
useEffect
for å legge til en 'resize'-hendelseslytter på vinduet. Når vinduet endrer størrelse, oppdatererhandleResize
-funksjonenwindowSize
-tilstanden. - Opprydding: Vi returnerer en oppryddingsfunksjon fra
useEffect
for å fjerne hendelseslytteren når komponenten avmonteres. Dette forhindrer minnelekkasjer. - Returner verdier: Hooken returnerer
windowSize
-objektet, som inneholder den nåværende bredden og høyden på vinduet.
Å bruke den egendefinerte Hooken i en komponent
Nå som vi har laget vår egendefinerte hook, la oss se hvordan vi kan bruke den i en React-komponent.
import React from 'react';
import useWindowSize from './useWindowSize';
function MyComponent() {
const { width, height } = useWindowSize();
return (
Vindusbredde: {width}px
Vindushøyde: {height}px
);
}
export default MyComponent;
Forklaring:
- Importer hooken: Vi importerer den egendefinerte hooken
useWindowSize
. - Kall på hooken: Vi kaller på
useWindowSize
-hooken inne i komponenten. - Få tilgang til verdier: Vi destrukturerer det returnerte objektet for å hente
width
- ogheight
-verdiene. - Render verdier: Vi rendrer bredde- og høydeverdiene i komponentens brukergrensesnitt.
Enhver komponent som bruker useWindowSize
vil automatisk oppdateres når vindusstørrelsen endres.
Mer komplekse eksempler
La oss utforske noen mer avanserte bruksområder for egendefinerte hooks.
Eksempel: useLocalStorage
Denne hooken lar deg enkelt lagre og hente data fra local storage.
import { useState, useEffect } from 'react';
function useLocalStorage(key, initialValue) {
// Tilstand for å lagre verdien vår
// Send startverdi til useState slik at logikken kun kjøres én gang
const [storedValue, setStoredValue] = useState(() => {
try {
// Hent fra local storage med nøkkel
const item = window.localStorage.getItem(key);
// Pars lagret json eller returner startverdi hvis ingen finnes
return item ? JSON.parse(item) : initialValue;
} catch (error) {
// Hvis feil, returner også startverdi
console.log(error);
return initialValue;
}
});
// Returner en innpakket versjon av useState sin setter-funksjon som ...
// ... lagrer den nye verdien til localStorage.
const setValue = (value) => {
try {
// Tillat at verdien er en funksjon slik at vi har samme API som useState
const valueToStore = value instanceof Function ? value(storedValue) : value;
// Lagre til local storage
window.localStorage.setItem(key, JSON.stringify(valueToStore));
// Lagre tilstand
setStoredValue(valueToStore);
} catch (error) {
// En mer avansert implementering ville håndtert feilsituasjonen
console.log(error);
}
};
useEffect(() => {
try {
const item = window.localStorage.getItem(key);
setStoredValue(item ? JSON.parse(item) : initialValue);
} catch (error) {
console.log(error);
}
}, [key, initialValue]);
return [storedValue, setValue];
}
export default useLocalStorage;
Bruk:
import React from 'react';
import useLocalStorage from './useLocalStorage';
function MyComponent() {
const [name, setName] = useLocalStorage('name', 'Guest');
return (
Hallo, {name}!
setName(e.target.value)}
/>
);
}
export default MyComponent;
Eksempel: useFetch
Denne hooken innkapsler logikken for å hente data fra et API.
import { useState, useEffect } from 'react';
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function fetchData() {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const json = await response.json();
setData(json);
setLoading(false);
} catch (error) {
setError(error);
setLoading(false);
}
}
fetchData();
}, [url]);
return { data, loading, error };
}
export default useFetch;
Bruk:
import React from 'react';
import useFetch from './useFetch';
function MyComponent() {
const { data, loading, error } = useFetch('https://jsonplaceholder.typicode.com/todos/1');
if (loading) return Laster...
;
if (error) return Feil: {error.message}
;
return (
Tittel: {data.title}
Fullført: {data.completed ? 'Ja' : 'Nei'}
);
}
export default MyComponent;
Beste praksis for egendefinerte Hooks
For å sikre at dine egendefinerte hooks er effektive og vedlikeholdbare, følg disse beste praksisene:
- Hold dem fokusert: Hver egendefinerte hook bør ha ett enkelt, veldefinert formål. Unngå å lage altfor komplekse hooks som prøver å gjøre for mye.
- Dokumenter dine hooks: Gi klar og konsis dokumentasjon for hver egendefinerte hook, som forklarer dens formål, input og output.
- Test dine hooks: Skriv enhetstester for dine egendefinerte hooks for å sikre at de fungerer korrekt og pålitelig.
- Bruk beskrivende navn: Velg beskrivende navn for dine egendefinerte hooks som tydelig indikerer deres formål.
- Håndter feil elegant: Implementer feilhåndtering i dine egendefinerte hooks for å forhindre uventet atferd og gi informative feilmeldinger.
- Vurder gjenbrukbarhet: Design dine egendefinerte hooks med gjenbrukbarhet i tankene. Gjør dem generiske nok til å kunne brukes i flere komponenter.
- Unngå over-abstraksjon: Ikke lag egendefinerte hooks for enkel logikk som lett kan håndteres inne i en komponent. Trekk kun ut logikk som er genuint gjenbrukbar og kompleks.
Vanlige fallgruver å unngå
- Bryte reglene for Hooks: Kall alltid hooks på toppnivået i din egendefinerte hook-funksjon, og kall dem kun fra React-funksjonskomponenter eller andre egendefinerte hooks.
- Ignorere avhengigheter i useEffect: Sørg for å inkludere alle nødvendige avhengigheter i avhengighetslisten til
useEffect
-hooken for å forhindre 'stale closures' og uventet atferd. - Skape uendelige løkker: Vær forsiktig når du oppdaterer tilstand inne i en
useEffect
-hook, da dette lett kan føre til uendelige løkker. Sørg for at oppdateringen er betinget og basert på endringer i avhengigheter. - Glemme opprydding: Inkluder alltid en oppryddingsfunksjon i
useEffect
for å fjerne hendelseslyttere, avbryte abonnementer og utføre andre oppryddingsoppgaver for å forhindre minnelekkasjer.
Avanserte mønstre
Komponering av egendefinerte Hooks
Egendefinerte hooks kan komponeres sammen for å skape mer kompleks logikk. For eksempel kan du kombinere en useLocalStorage
-hook med en useFetch
-hook for å automatisk lagre hentet data til local storage.
Dele logikk mellom Hooks
Hvis flere egendefinerte hooks deler felles logikk, kan du trekke ut den logikken i en separat hjelpefunksjon og gjenbruke den i begge hooks.
Bruke Context med egendefinerte Hooks
Egendefinerte hooks kan brukes sammen med React Context for å få tilgang til og oppdatere global tilstand. Dette lar deg lage gjenbrukbare komponenter som er bevisste på og kan interagere med applikasjonens globale tilstand.
Eksempler fra den virkelige verden
Her er noen eksempler på hvordan egendefinerte hooks kan brukes i virkelige applikasjoner:
- Skjemavalidering: Lag en
useForm
-hook for å håndtere skjemastatus, validering og innsending. - Autentisering: Implementer en
useAuth
-hook for å håndtere brukerautentisering og autorisasjon. - Temahåndtering: Utvikle en
useTheme
-hook for å bytte mellom forskjellige temaer (lys, mørk, etc.). - Geoposisjonering: Bygg en
useGeolocation
-hook for å spore brukerens nåværende posisjon. - Scroll-deteksjon: Lag en
useScroll
-hook for å oppdage når brukeren har scrollet til et bestemt punkt på siden.
Eksempel: useGeolocation-hook for flerkulturelle applikasjoner som karttjenester eller leveringstjenester
import { useState, useEffect } from 'react';
function useGeolocation() {
const [location, setLocation] = useState({
latitude: null,
longitude: null,
error: null,
});
useEffect(() => {
if (!navigator.geolocation) {
setLocation({
latitude: null,
longitude: null,
error: 'Geoposisjonering støttes ikke av denne nettleseren.',
});
return;
}
const watchId = navigator.geolocation.watchPosition(
(position) => {
setLocation({
latitude: position.coords.latitude,
longitude: position.coords.longitude,
error: null,
});
},
(error) => {
setLocation({
latitude: null,
longitude: null,
error: error.message,
});
}
);
return () => navigator.geolocation.clearWatch(watchId);
}, []);
return location;
}
export default useGeolocation;
Konklusjon
Egendefinerte hooks er et kraftig verktøy for å skrive renere, mer gjenbrukbar og mer vedlikeholdbar React-kode. Ved å innkapsle kompleks logikk i egendefinerte hooks kan du forenkle komponentene dine, redusere kodeduplisering og forbedre den overordnede strukturen i applikasjonene dine. Omfavn egendefinerte hooks og frigjør potensialet deres til å bygge mer robuste og skalerbare React-applikasjoner.
Start med å identifisere områder i din eksisterende kodebase der logikk gjentas på tvers av flere komponenter. Deretter, refaktorer den logikken til egendefinerte hooks. Over tid vil du bygge et bibliotek av gjenbrukbare hooks som vil akselerere utviklingsprosessen og forbedre kvaliteten på koden din.
Husk å følge beste praksis, unngå vanlige fallgruver og utforske avanserte mønstre for å få mest mulig ut av egendefinerte hooks. Med øvelse og erfaring vil du bli en mester i egendefinerte hooks og en mer effektiv React-utvikler.