Frigør potentialet i genanvendelig logik i dine React-applikationer med custom hooks. Lær at skabe og udnytte custom hooks for renere og mere vedligeholdelig kode.
Custom Hooks: Genanvendelige Logikmønstre i React
React Hooks revolutionerede den måde, vi skriver React-komponenter på, ved at introducere state- og livscyklusfunktioner til funktionelle komponenter. Blandt de mange fordele, de tilbyder, skiller custom hooks sig ud som en kraftfuld mekanisme til at udtrække og genbruge logik på tværs af flere komponenter. Dette blogindlæg vil dykke dybt ned i verdenen af custom hooks og udforske deres fordele, oprettelse og brug med praktiske eksempler.
Hvad er Custom Hooks?
Grundlæggende er en custom hook en JavaScript-funktion, der starter med ordet "use" og kan kalde andre hooks. De giver dig mulighed for at udtrække komponentlogik til genanvendelige funktioner. Dette er en effektiv måde at dele stateful logik, sideeffekter eller anden kompleks adfærd mellem komponenter uden at ty til render props, higher-order components eller andre komplekse mønstre.
Nøglekarakteristika for Custom Hooks:
- Navnekonvention: Custom hooks skal starte med ordet "use". Dette signalerer til React, at funktionen indeholder hooks og skal følge reglerne for hooks.
- Genanvendelighed: Det primære formål er at indkapsle genanvendelig logik, hvilket gør det nemt at dele funktionalitet mellem komponenter.
- Stateful Logik: Custom hooks kan håndtere deres egen state ved hjælp af
useState
-hooken, hvilket giver dem mulighed for at indkapsle kompleks stateful adfærd. - Sideeffekter: De kan også udføre sideeffekter ved hjælp af
useEffect
-hooken, hvilket muliggør integration med eksterne API'er, datahentning og mere. - Sammensættelige: Custom hooks kan kalde andre hooks, hvilket giver dig mulighed for at bygge kompleks logik ved at sammensætte mindre, mere fokuserede hooks.
Fordele ved at bruge Custom Hooks
Custom hooks tilbyder flere betydelige fordele i React-udvikling:
- Genanvendelighed af kode: Den mest åbenlyse fordel er muligheden for at genbruge logik på tværs af flere komponenter. Dette reducerer kodeduplikering og fremmer en mere DRY (Don't Repeat Yourself) kodebase.
- Forbedret Læsbarhed: Ved at udtrække kompleks logik i separate custom hooks bliver dine komponenter renere og lettere at forstå. Den centrale komponentlogik forbliver fokuseret på at rendere UI'en.
- Forbedret Vedligeholdelse: Når logik er indkapslet i custom hooks, kan ændringer og fejlrettelser anvendes ét enkelt sted, hvilket reducerer risikoen for at introducere fejl i flere komponenter.
- Testbarhed: Custom hooks kan nemt testes isoleret, hvilket sikrer, at den genanvendelige logik fungerer korrekt uafhængigt af de komponenter, der bruger dem.
- Forenklede Komponenter: Custom hooks hjælper med at rydde op i komponenter, hvilket gør dem mindre ordrige og mere fokuserede på deres primære formål.
Oprettelse af din første Custom Hook
Lad os illustrere oprettelsen af en custom hook med et praktisk eksempel: en hook, der sporer vinduesstørrelsen.
Eksempel: useWindowSize
Denne hook returnerer den aktuelle bredde og højde på browservinduet. Den vil også opdatere disse værdier, når vinduet ændres i 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);
// Remove event listener on cleanup
return () => window.removeEventListener('resize', handleResize);
}, []); // Empty array ensures that effect is only run on mount
return windowSize;
}
export default useWindowSize;
Forklaring:
- Importer nødvendige Hooks: Vi importerer
useState
oguseEffect
fra React. - Definer hooken: Vi opretter en funktion ved navn
useWindowSize
, som overholder navnekonventionen. - Initialiser State: Vi bruger
useState
til at initialiserewindowSize
-state med den indledende bredde og højde på vinduet. - Opsæt Event Listener: Vi bruger
useEffect
til at tilføje en 'resize' event listener til vinduet. Når vinduet ændres i størrelse, opdatererhandleResize
-funktionenwindowSize
-state. - Oprydning: Vi returnerer en oprydningsfunktion fra
useEffect
for at fjerne event listeneren, når komponenten afmonteres. Dette forhindrer hukommelseslækager. - Returner værdier: Hooken returnerer
windowSize
-objektet, som indeholder den aktuelle bredde og højde på vinduet.
Brug af en Custom Hook i en Komponent
Nu hvor vi har oprettet vores custom hook, lad os se, hvordan man bruger den i en React-komponent.
import React from 'react';
import useWindowSize from './useWindowSize';
function MyComponent() {
const { width, height } = useWindowSize();
return (
Vinduesbredde: {width}px
Vindueshøjde: {height}px
);
}
export default MyComponent;
Forklaring:
- Importer hooken: Vi importerer
useWindowSize
custom hooken. - Kald hooken: Vi kalder
useWindowSize
-hooken inde i komponenten. - Få adgang til værdier: Vi destrukturerer det returnerede objekt for at få
width
- ogheight
-værdierne. - Render værdier: Vi renderer bredde- og højdeværdierne i komponentens UI.
Enhver komponent, der bruger useWindowSize
, vil automatisk blive opdateret, når vinduesstørrelsen ændres.
Mere komplekse eksempler
Lad os udforske nogle mere avancerede anvendelsesmuligheder for custom hooks.
Eksempel: useLocalStorage
Denne hook giver dig mulighed for nemt at gemme og hente data fra local storage.
import { useState, useEffect } from 'react';
function useLocalStorage(key, initialValue) {
// State to store our value
// Pass initial value to useState so logic is only executed once
const [storedValue, setStoredValue] = useState(() => {
try {
// Get from local storage by key
const item = window.localStorage.getItem(key);
// Parse stored json or if none return initialValue
return item ? JSON.parse(item) : initialValue;
} catch (error) {
// If error also return initialValue
console.log(error);
return initialValue;
}
});
// Return a wrapped version of useState's setter function that ...
// ... persists the new value to localStorage.
const setValue = (value) => {
try {
// Allow value to be a function so we have same API as useState
const valueToStore = value instanceof Function ? value(storedValue) : value;
// Save to local storage
window.localStorage.setItem(key, JSON.stringify(valueToStore));
// Save state
setStoredValue(valueToStore);
} catch (error) {
// A more advanced implementation would handle the error case
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;
Anvendelse:
import React from 'react';
import useLocalStorage from './useLocalStorage';
function MyComponent() {
const [name, setName] = useLocalStorage('name', 'Gæst');
return (
Hej, {name}!
setName(e.target.value)}
/>
);
}
export default MyComponent;
Eksempel: useFetch
Denne hook indkapsler logikken for at 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;
Anvendelse:
import React from 'react';
import useFetch from './useFetch';
function MyComponent() {
const { data, loading, error } = useFetch('https://jsonplaceholder.typicode.com/todos/1');
if (loading) return Indlæser...
;
if (error) return Fejl: {error.message}
;
return (
Titel: {data.title}
Fuldført: {data.completed ? 'Ja' : 'Nej'}
);
}
export default MyComponent;
Bedste Praksis for Custom Hooks
For at sikre, at dine custom hooks er effektive og vedligeholdelige, skal du følge disse bedste praksisser:
- Hold dem fokuserede: Hver custom hook bør have et enkelt, veldefineret formål. Undgå at skabe alt for komplekse hooks, der forsøger at gøre for meget.
- Dokumenter dine hooks: Giv klar og koncis dokumentation for hver custom hook, der forklarer dens formål, input og output.
- Test dine hooks: Skriv enhedstests for dine custom hooks for at sikre, at de fungerer korrekt og pålideligt.
- Brug beskrivende navne: Vælg beskrivende navne til dine custom hooks, der tydeligt angiver deres formål.
- Håndter fejl elegant: Implementer fejlhåndtering i dine custom hooks for at forhindre uventet adfærd og give informative fejlmeddelelser.
- Overvej genanvendelighed: Design dine custom hooks med genanvendelighed for øje. Gør dem generiske nok til at kunne bruges i flere komponenter.
- Undgå over-abstraktion: Opret ikke custom hooks for simpel logik, der let kan håndteres i en komponent. Udtræk kun logik, der er virkelig genanvendelig og kompleks.
Almindelige faldgruber at undgå
- At bryde reglerne for hooks: Kald altid hooks på øverste niveau i din custom hook-funktion og kald dem kun fra React-funktionskomponenter eller andre custom hooks.
- Ignorering af afhængigheder i useEffect: Sørg for at inkludere alle nødvendige afhængigheder i afhængighedsarrayet for
useEffect
-hooken for at forhindre forældede closures og uventet adfærd. - Oprettelse af uendelige loops: Vær forsigtig, når du opdaterer state i en
useEffect
-hook, da dette let kan føre til uendelige loops. Sørg for, at opdateringen er betinget og baseret på ændringer i afhængigheder. - At glemme oprydning: Inkluder altid en oprydningsfunktion i
useEffect
for at fjerne event listeners, annullere abonnementer og udføre andre oprydningsopgaver for at forhindre hukommelseslækager.
Avancerede Mønstre
Sammensætning af Custom Hooks
Custom hooks kan sammensættes for at skabe mere kompleks logik. For eksempel kan du kombinere en useLocalStorage
-hook med en useFetch
-hook for automatisk at gemme hentede data i local storage.
Deling af logik mellem hooks
Hvis flere custom hooks deler fælles logik, kan du udtrække den logik til en separat hjælpefunktion og genbruge den i begge hooks.
Brug af Context med Custom Hooks
Custom hooks kan bruges i forbindelse med React Context for at få adgang til og opdatere global state. Dette giver dig mulighed for at skabe genanvendelige komponenter, der er bevidste om og kan interagere med applikationens globale state.
Eksempler fra den virkelige verden
Her er nogle eksempler på, hvordan custom hooks kan bruges i virkelige applikationer:
- Formularvalidering: Opret en
useForm
-hook til at håndtere formularens state, validering og indsendelse. - Autentificering: Implementer en
useAuth
-hook til at håndtere brugerautentificering og -autorisation. - Temahåndtering: Udvikl en
useTheme
-hook til at skifte mellem forskellige temaer (lys, mørk osv.). - Geolokation: Byg en
useGeolocation
-hook til at spore brugerens aktuelle placering. - Scroll-detektion: Opret en
useScroll
-hook til at registrere, hvornår brugeren har scrollet til et bestemt punkt på siden.
Eksempel: useGeolocation hook til tværkulturelle applikationer som kortlægning 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: 'Geolocation understøttes ikke af denne browser.',
});
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;
Konklusion
Custom hooks er et kraftfuldt værktøj til at skrive renere, mere genanvendelig og mere vedligeholdelig React-kode. Ved at indkapsle kompleks logik i custom hooks kan du forenkle dine komponenter, reducere kodeduplikering og forbedre den overordnede struktur af dine applikationer. Omfavn custom hooks og frigør deres potentiale til at bygge mere robuste og skalerbare React-applikationer.
Start med at identificere områder i din eksisterende kodebase, hvor logik gentages på tværs af flere komponenter. Refaktorér derefter den logik til custom hooks. Over tid vil du opbygge et bibliotek af genanvendelige hooks, der vil fremskynde din udviklingsproces og forbedre kvaliteten af din kode.
Husk at følge bedste praksis, undgå almindelige faldgruber og udforske avancerede mønstre for at få mest muligt ud af custom hooks. Med øvelse og erfaring vil du blive en mester i custom hooks og en mere effektiv React-udvikler.