Ontgrendel de kracht van herbruikbare logica in uw React-applicaties met custom hooks. Leer hoe u custom hooks creëert en benut voor schonere, beter onderhoudbare code.
Custom Hooks: Herbruikbare Logica Patronen in React
React Hooks hebben de manier waarop we React-componenten schrijven radicaal veranderd door state- en lifecycle-functionaliteiten te introduceren in functionele componenten. Onder de vele voordelen die ze bieden, springen custom hooks eruit als een krachtig mechanisme voor het extraheren en hergebruiken van logica over meerdere componenten. Deze blogpost duikt diep in de wereld van custom hooks en verkent hun voordelen, creatie en gebruik met praktische voorbeelden.
Wat zijn Custom Hooks?
In essentie is een custom hook een JavaScript-functie die begint met het woord "use" en andere hooks kan aanroepen. Ze stellen u in staat om componentlogica te extraheren in herbruikbare functies. Dit is een krachtige manier om stateful logica, neveneffecten of ander complex gedrag te delen tussen componenten zonder toevlucht te nemen tot render props, higher-order components of andere complexe patronen.
Belangrijkste Kenmerken van Custom Hooks:
- Naamgevingsconventie: Custom hooks moeten beginnen met het woord "use". Dit signaleert aan React dat de functie hooks bevat en de regels van hooks moet volgen.
- Herbruikbaarheid: Het primaire doel is om herbruikbare logica te encapsuleren, waardoor het gemakkelijk wordt om functionaliteit tussen componenten te delen.
- Stateful Logica: Custom hooks kunnen hun eigen state beheren met de
useState
hook, waardoor ze complex stateful gedrag kunnen inkapselen. - Neveneffecten: Ze kunnen ook neveneffecten uitvoeren met de
useEffect
hook, wat integratie met externe API's, data ophalen en meer mogelijk maakt. - Composeerbaar: Custom hooks kunnen andere hooks aanroepen, waardoor u complexe logica kunt opbouwen door kleinere, meer gefocuste hooks samen te stellen.
Voordelen van het Gebruik van Custom Hooks
Custom hooks bieden verschillende significante voordelen in React-ontwikkeling:
- Herbruikbaarheid van Code: Het meest duidelijke voordeel is de mogelijkheid om logica te hergebruiken over meerdere componenten. Dit vermindert code-duplicatie en bevordert een meer DRY (Don't Repeat Yourself) codebase.
- Verbeterde Leesbaarheid: Door complexe logica te extraheren in afzonderlijke custom hooks, worden uw componenten schoner en gemakkelijker te begrijpen. De kernlogica van het component blijft gericht op het renderen van de UI.
- Verbeterde Onderhoudbaarheid: Wanneer logica is ingekapseld in custom hooks, kunnen wijzigingen en bugfixes op één enkele locatie worden toegepast, wat het risico op het introduceren van fouten in meerdere componenten vermindert.
- Testbaarheid: Custom hooks kunnen eenvoudig geïsoleerd worden getest, wat ervoor zorgt dat de herbruikbare logica correct functioneert, onafhankelijk van de componenten die ze gebruiken.
- Vereenvoudigde Componenten: Custom hooks helpen componenten op te schonen, waardoor ze minder uitgebreid en meer gericht zijn op hun primaire doel.
Je Eerste Custom Hook Maken
Laten we de creatie van een custom hook illustreren met een praktisch voorbeeld: een hook die de venstergrootte bijhoudt.
Voorbeeld: useWindowSize
Deze hook retourneert de huidige breedte en hoogte van het browservenster. Hij zal deze waarden ook bijwerken wanneer het venster wordt vergroot of verkleind.
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);
// Verwijder event listener bij het opruimen
return () => window.removeEventListener('resize', handleResize);
}, []); // Lege array zorgt ervoor dat het effect alleen wordt uitgevoerd bij het mounten
return windowSize;
}
export default useWindowSize;
Uitleg:
- Importeer Noodzakelijke Hooks: We importeren
useState
enuseEffect
uit React. - Definieer de Hook: We creëren een functie genaamd
useWindowSize
, die voldoet aan de naamgevingsconventie. - Initialiseer State: We gebruiken
useState
om dewindowSize
-state te initialiseren met de initiële breedte en hoogte van het venster. - Stel Event Listener in: We gebruiken
useEffect
om een resize event listener aan het venster toe te voegen. Wanneer de venstergrootte verandert, werkt dehandleResize
-functie dewindowSize
-state bij. - Opruimen: We retourneren een opruimfunctie van
useEffect
om de event listener te verwijderen wanneer het component unmount. Dit voorkomt geheugenlekken. - Retourneer Waarden: De hook retourneert het
windowSize
-object, dat de huidige breedte en hoogte van het venster bevat.
De Custom Hook in een Component Gebruiken
Nu we onze custom hook hebben gemaakt, laten we zien hoe we deze in een React-component kunnen gebruiken.
import React from 'react';
import useWindowSize from './useWindowSize';
function MyComponent() {
const { width, height } = useWindowSize();
return (
Vensterbreedte: {width}px
Vensterhoogte: {height}px
);
}
export default MyComponent;
Uitleg:
- Importeer de Hook: We importeren de
useWindowSize
custom hook. - Roep de Hook aan: We roepen de
useWindowSize
-hook aan binnen het component. - Krijg Toegang tot Waarden: We destructureren het geretourneerde object om de
width
- enheight
-waarden te krijgen. - Render Waarden: We renderen de breedte- en hoogtewaarden in de UI van het component.
Elk component dat useWindowSize
gebruikt, zal automatisch updaten wanneer de venstergrootte verandert.
Complexere Voorbeelden
Laten we enkele meer geavanceerde gebruiksscenario's voor custom hooks bekijken.
Voorbeeld: useLocalStorage
Met deze hook kunt u eenvoudig gegevens opslaan en ophalen uit de lokale opslag.
import { useState, useEffect } from 'react';
function useLocalStorage(key, initialValue) {
// State om onze waarde op te slaan
// Geef de initiële waarde door aan useState zodat de logica slechts één keer wordt uitgevoerd
const [storedValue, setStoredValue] = useState(() => {
try {
// Haal op uit local storage via de key
const item = window.localStorage.getItem(key);
// Parse de opgeslagen JSON of retourneer de beginwaarde als er niets is
return item ? JSON.parse(item) : initialValue;
} catch (error) {
// Retourneer ook de beginwaarde bij een fout
console.log(error);
return initialValue;
}
});
// Retourneer een 'wrapped' versie van de setter-functie van useState die ...
// ... de nieuwe waarde persistent maakt in localStorage.
const setValue = (value) => {
try {
// Sta toe dat de waarde een functie is, zodat we dezelfde API hebben als useState
const valueToStore = value instanceof Function ? value(storedValue) : value;
// Sla op in local storage
window.localStorage.setItem(key, JSON.stringify(valueToStore));
// Sla de state op
setStoredValue(valueToStore);
} catch (error) {
// Een meer geavanceerde implementatie zou de foutsituatie afhandelen
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;
Gebruik:
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;
Voorbeeld: useFetch
Deze hook omvat de logica voor het ophalen van gegevens van een 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;
Gebruik:
import React from 'react';
import useFetch from './useFetch';
function MyComponent() {
const { data, loading, error } = useFetch('https://jsonplaceholder.typicode.com/todos/1');
if (loading) return Laden...
;
if (error) return Fout: {error.message}
;
return (
Titel: {data.title}
Voltooid: {data.completed ? 'Ja' : 'Nee'}
);
}
export default MyComponent;
Best Practices voor Custom Hooks
Om ervoor te zorgen dat uw custom hooks effectief en onderhoudbaar zijn, volgt u deze best practices:
- Houd ze Gefocust: Elke custom hook moet een enkel, goed gedefinieerd doel hebben. Vermijd het creëren van te complexe hooks die te veel proberen te doen.
- Documenteer Uw Hooks: Zorg voor duidelijke en beknopte documentatie voor elke custom hook, waarin het doel, de inputs en outputs worden uitgelegd.
- Test Uw Hooks: Schrijf unit tests voor uw custom hooks om ervoor te zorgen dat ze correct en betrouwbaar functioneren.
- Gebruik Beschrijvende Namen: Kies beschrijvende namen voor uw custom hooks die duidelijk hun doel aangeven.
- Handel Fouten Netjes Af: Implementeer foutafhandeling binnen uw custom hooks om onverwacht gedrag te voorkomen en informatieve foutmeldingen te geven.
- Denk aan Herbruikbaarheid: Ontwerp uw custom hooks met herbruikbaarheid in gedachten. Maak ze generiek genoeg om in meerdere componenten te worden gebruikt.
- Vermijd Over-Abstractie: Creëer geen custom hooks voor eenvoudige logica die gemakkelijk binnen een component kan worden afgehandeld. Extraheer alleen logica die echt herbruikbaar en complex is.
Veelvoorkomende Valkuilen om te Vermijden
- De Regels van Hooks Breken: Roep hooks altijd aan op het hoogste niveau van uw custom hook-functie en roep ze alleen aan vanuit React-functiecomponenten of andere custom hooks.
- Afhankelijkheden in useEffect Negeren: Zorg ervoor dat u alle noodzakelijke afhankelijkheden opneemt in de dependency array van de
useEffect
hook om verouderde closures en onverwacht gedrag te voorkomen. - Oneindige Loops Creëren: Wees voorzichtig bij het bijwerken van state binnen een
useEffect
-hook, omdat dit gemakkelijk tot oneindige loops kan leiden. Zorg ervoor dat de update voorwaardelijk is en gebaseerd op veranderingen in afhankelijkheden. - Opruimen Vergeten: Neem altijd een opruimfunctie op in
useEffect
om event listeners te verwijderen, abonnementen te annuleren en andere opruimtaken uit te voeren om geheugenlekken te voorkomen.
Geavanceerde Patronen
Custom Hooks Samenstellen
Custom hooks kunnen samen worden gesteld om complexere logica te creëren. U zou bijvoorbeeld een useLocalStorage
-hook kunnen combineren met een useFetch
-hook om opgehaalde gegevens automatisch in de lokale opslag te bewaren.
Logica Delen Tussen Hooks
Als meerdere custom hooks gemeenschappelijke logica delen, kunt u die logica extraheren in een aparte utility-functie en deze in beide hooks hergebruiken.
Context Gebruiken met Custom Hooks
Custom hooks kunnen in combinatie met React Context worden gebruikt om toegang te krijgen tot en het bijwerken van globale state. Hiermee kunt u herbruikbare componenten maken die op de hoogte zijn van en kunnen interageren met de globale state van de applicatie.
Voorbeelden uit de Praktijk
Hier zijn enkele voorbeelden van hoe custom hooks kunnen worden gebruikt in real-world applicaties:
- Formuliervalidatie: Creëer een
useForm
-hook om formulierstatus, validatie en verzending af te handelen. - Authenticatie: Implementeer een
useAuth
-hook om gebruikersauthenticatie en -autorisatie te beheren. - Themabeheer: Ontwikkel een
useTheme
-hook om te schakelen tussen verschillende thema's (licht, donker, etc.). - Geolocatie: Bouw een
useGeolocation
-hook om de huidige locatie van de gebruiker te volgen. - Scroll Detectie: Creëer een
useScroll
-hook om te detecteren wanneer de gebruiker naar een bepaald punt op de pagina heeft gescrold.
Voorbeeld: useGeolocation-hook voor cross-culturele applicaties zoals kaarten of bezorgdiensten
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: 'Geolocatie wordt niet ondersteund door deze 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;
Conclusie
Custom hooks zijn een krachtig hulpmiddel voor het schrijven van schonere, meer herbruikbare en beter onderhoudbare React-code. Door complexe logica in te kapselen in custom hooks, kunt u uw componenten vereenvoudigen, code-duplicatie verminderen en de algehele structuur van uw applicaties verbeteren. Omarm custom hooks en ontgrendel hun potentieel om robuustere en schaalbaardere React-applicaties te bouwen.
Begin met het identificeren van gebieden in uw bestaande codebase waar logica wordt herhaald over meerdere componenten. Refactor die logica vervolgens naar custom hooks. Na verloop van tijd bouwt u een bibliotheek van herbruikbare hooks op die uw ontwikkelingsproces zal versnellen en de kwaliteit van uw code zal verbeteren.
Vergeet niet om best practices te volgen, veelvoorkomende valkuilen te vermijden en geavanceerde patronen te verkennen om het meeste uit custom hooks te halen. Met oefening en ervaring wordt u een meester in custom hooks en een effectievere React-ontwikkelaar.