Frigör kraften i återanvändbar logik i dina React-applikationer med anpassade krokar. Lär dig hur du skapar och använder anpassade krokar för renare och mer underhållbar kod.
Anpassade Krokar: Återanvändbara Logikmönster i React
React Hooks revolutionerade sättet vi skriver React-komponenter på genom att introducera tillstånd och livscykelfunktioner i funktionella komponenter. Bland de många fördelarna de erbjuder, utmärker sig anpassade krokar som en kraftfull mekanism för att extrahera och återanvända logik över flera komponenter. Detta blogginlägg kommer att djupdyka i världen av anpassade krokar, och utforska deras fördelar, skapande och användning med praktiska exempel.
Vad är Anpassade Krokar?
I grund och botten är en anpassad krok en JavaScript-funktion som börjar med ordet "use" och kan anropa andra krokar. De låter dig extrahera komponentlogik till återanvändbara funktioner. Detta är ett kraftfullt sätt att dela tillståndsbaserad logik, sidoeffekter eller andra komplexa beteenden mellan komponenter utan att behöva använda render props, högre ordningens komponenter eller andra komplexa mönster.
Nyckelegenskaper för Anpassade Krokar:
- Namnkonvention: Anpassade krokar måste börja med ordet "use". Detta signalerar till React att funktionen innehåller krokar och ska följa reglerna för krokar.
- Återanvändbarhet: Det primära syftet är att kapsla in återanvändbar logik, vilket gör det enkelt att dela funktionalitet mellan komponenter.
- Tillståndsbaserad Logik: Anpassade krokar kan hantera sitt eget tillstånd med hjälp av
useState
-kroken, vilket gör att de kan kapsla in komplext tillståndsbaserat beteende. - Sidoeffekter: De kan också utföra sidoeffekter med hjälp av
useEffect
-kroken, vilket möjliggör integration med externa API:er, datahämtning och mer. - Komponerbara: Anpassade krokar kan anropa andra krokar, vilket gör att du kan bygga komplex logik genom att komponera mindre, mer fokuserade krokar.
Fördelar med att Använda Anpassade Krokar
Anpassade krokar erbjuder flera betydande fördelar i React-utveckling:
- Återanvändning av Kod: Den mest uppenbara fördelen är förmågan att återanvända logik över flera komponenter. Detta minskar kodduplicering och främjar en mer DRY (Don't Repeat Yourself) kodbas.
- Förbättrad Läsbarhet: Genom att extrahera komplex logik till separata anpassade krokar blir dina komponenter renare och lättare att förstå. Kärnlogiken i komponenten förblir fokuserad på att rendera UI:t.
- Förbättrad Underhållbarhet: När logik är inkapslad i anpassade krokar kan ändringar och buggfixar appliceras på en enda plats, vilket minskar risken för att introducera fel i flera komponenter.
- Testbarhet: Anpassade krokar kan enkelt testas isolerat, vilket säkerställer att den återanvändbara logiken fungerar korrekt oberoende av de komponenter som använder dem.
- Förenklade Komponenter: Anpassade krokar hjälper till att rensa upp i komponenter, vilket gör dem mindre mångordiga och mer fokuserade på sitt primära syfte.
Skapa Din Första Anpassade Krok
Låt oss illustrera skapandet av en anpassad krok med ett praktiskt exempel: en krok som spårar fönsterstorleken.
Exempel: useWindowSize
Denna krok kommer att returnera den aktuella bredden och höjden på webbläsarfönstret. Den kommer också att uppdatera dessa värden när fönstret storleksändras.
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);
// Ta bort händelselyssnare vid städning
return () => window.removeEventListener('resize', handleResize);
}, []); // Tom array säkerställer att effekten endast körs vid montering
return windowSize;
}
export default useWindowSize;
Förklaring:
- Importera Nödvändiga Krokar: Vi importerar
useState
ochuseEffect
från React. - Definiera Kroken: Vi skapar en funktion med namnet
useWindowSize
, enligt namnkonventionen. - Initiera Tillstånd: Vi använder
useState
för att initierawindowSize
-tillståndet med fönstrets initiala bredd och höjd. - Sätt Upp Händelselyssnare: Vi använder
useEffect
för att lägga till en 'resize'-händelselyssnare på fönstret. När fönstret storleksändras uppdaterarhandleResize
-funktionenwindowSize
-tillståndet. - Städning: Vi returnerar en städningsfunktion från
useEffect
för att ta bort händelselyssnaren när komponenten avmonteras. Detta förhindrar minnesläckor. - Returnera Värden: Kroken returnerar
windowSize
-objektet, som innehåller fönstrets aktuella bredd och höjd.
Använda den Anpassade Kroken i en Komponent
Nu när vi har skapat vår anpassade krok, låt oss se hur man använder den i en React-komponent.
import React from 'react';
import useWindowSize from './useWindowSize';
function MyComponent() {
const { width, height } = useWindowSize();
return (
Window width: {width}px
Window height: {height}px
);
}
export default MyComponent;
Förklaring:
- Importera Kroken: Vi importerar den anpassade kroken
useWindowSize
. - Anropa Kroken: Vi anropar
useWindowSize
-kroken inuti komponenten. - Åtkomst till Värden: Vi destrukurerar det returnerade objektet för att få
width
- ochheight
-värdena. - Rendera Värden: Vi renderar bredd- och höjdvärdena i komponentens UI.
Alla komponenter som använder useWindowSize
kommer automatiskt att uppdateras när fönsterstorleken ändras.
Mer Komplexa Exempel
Låt oss utforska några mer avancerade användningsfall för anpassade krokar.
Exempel: useLocalStorage
Denna krok låter dig enkelt lagra och hämta data från local storage.
import { useState, useEffect } from 'react';
function useLocalStorage(key, initialValue) {
// Tillstånd för att lagra vårt värde
// Skicka initialvärde till useState så att logiken bara körs en gång
const [storedValue, setStoredValue] = useState(() => {
try {
// Hämta från local storage med nyckel
const item = window.localStorage.getItem(key);
// Parsa lagrad json eller returnera initialValue om ingen finns
return item ? JSON.parse(item) : initialValue;
} catch (error) {
// Om fel, returnera också initialValue
console.log(error);
return initialValue;
}
});
// Returnera en inlindad version av useStates setter-funktion som ...
// ... sparar det nya värdet till localStorage.
const setValue = (value) => {
try {
// Tillåt att värdet är en funktion så att vi har samma API som useState
const valueToStore = value instanceof Function ? value(storedValue) : value;
// Spara till local storage
window.localStorage.setItem(key, JSON.stringify(valueToStore));
// Spara tillstånd
setStoredValue(valueToStore);
} catch (error) {
// En mer avancerad implementation skulle hantera fel fallet
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;
Användning:
import React from 'react';
import useLocalStorage from './useLocalStorage';
function MyComponent() {
const [name, setName] = useLocalStorage('name', 'Guest');
return (
Hello, {name}!
setName(e.target.value)}
/>
);
}
export default MyComponent;
Exempel: useFetch
Denna krok kapslar in logiken för att hämta data från ett 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;
Användning:
import React from 'react';
import useFetch from './useFetch';
function MyComponent() {
const { data, loading, error } = useFetch('https://jsonplaceholder.typicode.com/todos/1');
if (loading) return Loading...
;
if (error) return Error: {error.message}
;
return (
Title: {data.title}
Completed: {data.completed ? 'Yes' : 'No'}
);
}
export default MyComponent;
Bästa Praxis för Anpassade Krokar
För att säkerställa att dina anpassade krokar är effektiva och underhållbara, följ dessa bästa praxis:
- Håll Dem Fokuserade: Varje anpassad krok bör ha ett enda, väldefinierat syfte. Undvik att skapa överdrivet komplexa krokar som försöker göra för mycket.
- Dokumentera Dina Krokar: Tillhandahåll tydlig och koncis dokumentation för varje anpassad krok, där du förklarar dess syfte, indata och utdata.
- Testa Dina Krokar: Skriv enhetstester för dina anpassade krokar för att säkerställa att de fungerar korrekt och pålitligt.
- Använd Beskrivande Namn: Välj beskrivande namn för dina anpassade krokar som tydligt indikerar deras syfte.
- Hantera Fel Elegant: Implementera felhantering inom dina anpassade krokar för att förhindra oväntat beteende och ge informativa felmeddelanden.
- Tänk på Återanvändbarhet: Designa dina anpassade krokar med återanvändbarhet i åtanke. Gör dem tillräckligt generiska för att kunna användas i flera komponenter.
- Undvik Överabstraktion: Skapa inte anpassade krokar för enkel logik som lätt kan hanteras inom en komponent. Extrahera endast logik som är verkligt återanvändbar och komplex.
Vanliga Fallgropar att Undvika
- Bryta mot Reglerna för Krokar: Anropa alltid krokar på den översta nivån i din anpassade krokfunktion och anropa dem endast från React-funktionskomponenter eller andra anpassade krokar.
- Ignorera Beroenden i useEffect: Se till att inkludera alla nödvändiga beroenden i beroendearrayen för
useEffect
-kroken för att förhindra inaktuella closures och oväntat beteende. - Skapa Oändliga Loopar: Var försiktig när du uppdaterar tillstånd inom en
useEffect
-krok, eftersom detta lätt kan leda till oändliga loopar. Se till att uppdateringen är villkorlig och baserad på ändringar i beroenden. - Glömma Städning: Inkludera alltid en städningsfunktion i
useEffect
för att ta bort händelselyssnare, avbryta prenumerationer och utföra andra städningsuppgifter för att förhindra minnesläckor.
Avancerade Mönster
Komponera Anpassade Krokar
Anpassade krokar kan komponeras tillsammans för att skapa mer komplex logik. Till exempel kan du kombinera en useLocalStorage
-krok med en useFetch
-krok för att automatiskt spara hämtad data till local storage.
Dela Logik Mellan Krokar
Om flera anpassade krokar delar gemensam logik kan du extrahera den logiken till en separat hjälpfunktion och återanvända den i båda krokarna.
Använda Context med Anpassade Krokar
Anpassade krokar kan användas tillsammans med React Context för att komma åt och uppdatera globalt tillstånd. Detta låter dig skapa återanvändbara komponenter som är medvetna om och kan interagera med applikationens globala tillstånd.
Verkliga Exempel
Här är några exempel på hur anpassade krokar kan användas i verkliga applikationer:
- Formulärvalidering: Skapa en
useForm
-krok för att hantera formulärtillstånd, validering och inskickning. - Autentisering: Implementera en
useAuth
-krok för att hantera användarautentisering och auktorisering. - Temahantering: Utveckla en
useTheme
-krok för att växla mellan olika teman (ljust, mörkt, etc.). - Geolokalisering: Bygg en
useGeolocation
-krok för att spåra användarens nuvarande position. - Scroll-detektering: Skapa en
useScroll
-krok för att upptäcka när användaren har scrollat till en viss punkt på sidan.
Exempel : useGeolocation-krok för tvärkulturella applikationer som karttjänster eller leveranstjänster
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 is not supported by this 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;
Slutsats
Anpassade krokar är ett kraftfullt verktyg för att skriva renare, mer återanvändbar och mer underhållbar React-kod. Genom att kapsla in komplex logik i anpassade krokar kan du förenkla dina komponenter, minska kodduplicering och förbättra den övergripande strukturen i dina applikationer. Omfamna anpassade krokar och frigör deras potential att bygga mer robusta och skalbara React-applikationer.
Börja med att identifiera områden i din befintliga kodbas där logik upprepas över flera komponenter. Refaktorera sedan den logiken till anpassade krokar. Med tiden kommer du att bygga ett bibliotek av återanvändbara krokar som kommer att påskynda din utvecklingsprocess och förbättra kvaliteten på din kod.
Kom ihåg att följa bästa praxis, undvika vanliga fallgropar och utforska avancerade mönster för att få ut det mesta av anpassade krokar. Med övning och erfarenhet kommer du att bli en mästare på anpassade krokar och en mer effektiv React-utvecklare.