stateful तर्क को फिर से उपयोग करने योग्य, composable, testable hooks में निकालें।
इस पाठ को Kodokon में खोलेंएक custom hook एक ऐसा फ़ंक्शन है जिसका नाम use से शुरू होता है और जो अन्य hooks कॉल करता है। यह stateful तर्क निकालता है, साझा state नहीं: हर कंपोनेंट जो इसे कॉल करता है उसे अपना ख़ुद का useState और useEffect मिलता है, पूरी तरह अलग-थलग। यह तर्क को अलग निकालने के लिए React का सबसे सीधा उपकरण है - जहाँ HOCs और render props पेड़ में परतें जोड़ते थे, वहाँ एक hook कंपोनेंट के शरीर में समा जाता है, आसानी से compose होता है, और टेस्ट करने में आसान है।
import { useEffect, useState } from "react";
function useDebouncedValue(value, delay = 300) {
const [debounced, setDebounced] = useState(value);
useEffect(() => {
const id = setTimeout(() => {
setDebounced(value);
}, delay);
return () => clearTimeout(id);
}, [value, delay]);
return debounced;
}use उपसर्ग सजावटी नहीं है: यही वह चीज़ है जो react-hooks ESLint plugin को आपके फ़ंक्शन के अंदर hooks के नियम जाँचने देती है - बिना शर्त कॉल, शीर्ष स्तर पर। लौटाए गए API के आकार का भी ध्यान रखें: जब उपयोग useState जैसा हो तो एक [value, setValue] tuple, और जैसे ही उजागर करने के लिए दो से अधिक चीज़ें हों तो named keys वाली एक object।
function useLocalStorage(key, initialValue) {
const [value, setValue] = useState(() => {
const stored = localStorage.getItem(key);
return stored !== null
? JSON.parse(stored)
: initialValue;
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue];
}Hooks compose होते हैं: एक hook अन्य hooks कॉल कर सकता है, जिनमें आपके अपने भी शामिल हैं। इसी तरह पठनीय व्यावसायिक abstractions उभरती हैं, जो generic बुनियादी ब्लॉकों पर बनी होती हैं। AbortController का cleanup फ़ंक्शन के साथ मेल पर ध्यान दें: इसके बिना, किसी पुराने input के लिए भेजा गया request सबसे नए के बाद जवाब दे सकता है और उसके परिणाम को अधिलेखित कर सकता है - search fields की क्लासिक race condition।
function useUserSearch(query) {
const debounced = useDebouncedValue(query, 400);
const [results, setResults] = useState([]);
useEffect(() => {
if (debounced === "") {
setResults([]);
return;
}
const controller = new AbortController();
fetch("/api/search?q=" + debounced, {
signal: controller.signal,
})
.then((res) => res.json())
.then(setResults)
.catch(() => {});
return () => controller.abort();
}, [debounced]);
return results;
}