useCallback एक React हुक है जो फ़ंक्शन का एक मेमोइज़्ड संस्करण लौटाता है जो रेंडरों के बीच तब तक नहीं बदलता जब तक उसकी निर्भरताएँ न बदलें। कंपोनेंट के अंदर सामान्य फ़ंक्शन घोषणा (जो हर रेंडर पर एक नया फ़ंक्शन बनाती है) के विपरीत, useCallback फ़ंक्शन रेफरेंस को स्थिर करता है, जो React.memo के माध्यम से ऑप्टिमाइज़ किए गए चाइल्ड कंपोनेंट्स के अनावश्यक री-रेंडर को रोकता है। React Documentation (2025) के अनुसार, useCallback केवल React.memo या स्थिर रेफरेंस पर निर्भर हुक के साथ ही उपयोगी है।
मुख्य बिंदु
useCallback React 16.8 में जोड़ा गया एक हुक है जो फ़ंक्शन को मेमोइज़ करता है: निर्भरताओं के बदलने तक समान रेफरेंस लौटाता है। useCallback के बिना, कंपोनेंट के अंदर प्रत्येक फ़ंक्शन घोषणा हर रेंडर पर एक नया फ़ंक्शन ऑब्जेक्ट बनाती है। प्रिमिटिव के लिए यह अदृश्य है, लेकिन ऐसे कॉलबैक को React.memo से ऑप्टिमाइज़ किए गए चाइल्ड कंपोनेंट्स में पास करते समय, प्रत्येक नया रेफरेंस चाइल्ड कंपोनेंट के री-रेंडर का कारण बनता है।
वाक्य रचना की दृष्टि से, useCallback फ़ंक्शन के लिए useMemo के समतुल्य है: useCallback(fn, deps), useMemo(() => fn, deps) के लिए शॉर्टहैंड है। React मेमोइज़्ड फ़ंक्शन को फ़ाइबर नोड के आंतरिक भंडारण में रखता है और हर रेंडर पर निर्भरताओं की तुलना करता है। यदि निर्भरताएँ नहीं बदली हैं (प्रत्येक आइटम के लिए Object.is), तो पिछला फ़ंक्शन लौटाया जाता है।
React Documentation — useCallback (2025) के अनुसार, प्रत्येक फ़ंक्शन को useCallback में लपेटना नहीं चाहिए। हुक की अपनी लागत है: हुक को कॉल करना, निर्भरताओं की तुलना करना और निर्भरता ऐरे के लिए मेमोरी आवंटित करना। यदि कंपोनेंट सरल है और उसमें React.memo के साथ गहरे ट्री नहीं हैं, तो useCallback केवल एप्लिकेशन को धीमा करेगा। ऑप्टिमाइज़ेशन मापने योग्य होना चाहिए, न कि सहज ज्ञान पर आधारित।
import { useCallback } from 'react';
function Parent() {
const [count, setCount] = useState(0);
// स्थिर रेफरेंस — निर्भरताओं के बदलने तक समान फ़ंक्शन
const handleClick = useCallback(() => {
setCount(prev => prev + 1);
}, []);
return <Child onClick={handleClick} />;
}
useCallback में मेमोइज़ेशन फ़ंक्शन कॉल के परिणाम को कैश करने पर आधारित है। React पहले रेंडर के समय बनाए गए क्लोज़र को संरक्षित करता है और बाद के रेंडरों पर उसे लौटाता है जब तक निर्भरताएँ अपरिवर्तित रहती हैं। फ़ाइबर नोड के अंदर, प्रत्येक useCallback कॉल हुक की लिंक्ड लिस्ट में एक नोड बनाता है, जहाँ पिछली निर्भरताएँ और मेमोइज़्ड मान संग्रहीत होते हैं।
निर्भरता तुलना सख्ती से Object.is के माध्यम से की जाती है — ऑब्जेक्ट या ऐरे की गहन जाँच के बिना एक सतही तुलना। यदि निर्भरता में कोई ऑब्जेक्ट या ऐरे है, तो हर रेंडर पर एक नया रेफरेंस परिवर्तन माना जाएगा। इसलिए, निर्भरता ऐरे में प्रिमिटिव मान या स्थिर रेफरेंस (जैसे useRef या useMemo से) होने चाहिए।
React Core Team — Optimization Guide (2024) के अनुसार, मेमोइज़ेशन की लागत में तीन घटक शामिल हैं: प्रत्येक रेंडर पर निर्भरता ऐरे आवंटित करना, Object.is के माध्यम से तत्वों को पार करना और तुलना करना, और पुनः निर्माण पर कचरा संग्रहण का संभावित ओवरहेड। सैकड़ों useCallback रैपर वाले कंपोनेंट के लिए, यह ध्यान देने योग्य हो सकता है — इसलिए हुक के उपयोग में चयनात्मकता महत्वपूर्ण है।
| परिदृश्य | useCallback के बिना | useCallback के साथ |
|---|---|---|
| फ़ंक्शन निर्माण | हर रेंडर पर नया | स्थिर deps के साथ समान |
| React.memo में पास करना | चाइल्ड री-रेंडर करता है | चाइल्ड री-रेंडर नहीं करता |
| useEffect ऐरे में | इफ़ेक्ट पुनः शुरू होता है | इफ़ेक्ट स्थिर रहता है |
| ओवरहेड | न्यूनतम | निर्भरता तुलना + मेमोरी |
एक व्यापक मिथक है कि useCallback स्वचालित रूप से प्रदर्शन में सुधार करता है। वास्तव में, अलगाव में (React.memo के बिना), useCallback निर्भरता तुलना की लागत के कारण एप्लिकेशन को थोड़ा धीमा भी कर देता है। हुक केवल तीन परिदृश्यों में वास्तविक लाभ देता है: React.memo कंपोनेंट्स के री-रेंडर को रोकना, useEffect में कॉलबैक को स्थिर करना, और कस्टम हुक्स में कॉलबैक पास करना जो रेफरेंस समानता पर निर्भर करते हैं।
नियम सरल है: जब तक आप React DevTools Profiler के माध्यम से प्रदर्शन समस्या का पता नहीं लगाते — useCallback का उपयोग न करें। React टीम ने बार-बार जोर दिया है कि समय से पहले ऑप्टिमाइज़ेशन सभी बुराइयों की जड़ है। पहले मेमोइज़ेशन के बिना साफ कोड लिखें, मापें, प्रोफाइलर में बाधा खोजें, और उसके बाद ही useCallback वहाँ जोड़ें जहाँ वास्तव में ज़रूरत हो।
// मापने योग्य ऑप्टिमाइज़ेशन: Child React.memo में लिपटा है
const Child = React.memo(({ onClick }) => {
console.log('Child पुनः रेंडर हुआ');
return <button onClick={onClick}>Click</button>;
});
function Parent() {
const handleClick = useCallback(() => {
console.log('क्लिक किया गया');
}, []);
return <Child onClick={handleClick} />;
}
Dan Abramov — Before You memo() (2024) के अनुसार, ओपन-सोर्स प्रोजेक्ट्स में useCallback के 90% से अधिक उपयोग अनावश्यक हैं। डेवलपर्स प्रभाव को मापे बिना "बस मामले में" हर फ़ंक्शन को लपेटते हैं। विकल्प: यदि चाइल्ड कंपोनेंट भारी है और उसका री-रेंडर महँगा है — React.memo + useCallback उचित है। यदि चाइल्ड कंपोनेंट हल्का है — री-रेंडर निर्भरता तुलना से सस्ता है।
पहला परिदृश्य — React.memo। यदि चाइल्ड कंपोनेंट React.memo में लिपटा है और एक प्रॉप के रूप में कॉलबैक फ़ंक्शन प्राप्त करता है, तो useCallback के बिना चाइल्ड कंपोनेंट हर पैरेंट रेंडर पर री-रेंडर करेगा, भले ही उसका अपना डेटा न बदला हो। useCallback रेफरेंस को स्थिर करता है, जिससे React.memo री-रेंडर को सही ढंग से छोड़ सकता है।
दूसरा परिदृश्य — निर्भरता में कॉलबैक के साथ useEffect। यदि कोई फ़ंक्शन useEffect निर्भरता ऐरे में पास किया जाता है, तो प्रत्येक नया रेफरेंस इफ़ेक्ट को पुनः शुरू करेगा। useCallback सुनिश्चित करता है कि रेफरेंस स्थिर है, और इफ़ेक्ट केवल तब चलता है जब वास्तविक डेटा बदलता है, हर रेंडर पर नहीं। यह विशेष रूप से सब्सक्रिप्शन और अनुरोधों के लिए महत्वपूर्ण है।
// स्थिर useEffect निर्भरता के लिए useCallback
const fetchData = useCallback(async (id) => {
const res = await fetch(`/api/${id}`);
setData(res.data);
}, []); // स्थिर रेफरेंस, कभी पुनः नहीं बनता
useEffect(() => {
fetchData(props.id);
}, [props.id, fetchData]); // इफ़ेक्ट केवल तब चलता है जब props.id बदलता है
useCallback और useMemo के बीच मुख्य अंतर यह है कि प्रत्येक क्या मेमोइज़ करता है। useCallback एक फ़ंक्शन को मेमोइज़ करता है: useCallback(fn, deps) fn लौटाता है (वही या पिछला संस्करण)। useMemo फ़ंक्शन कॉल के परिणाम को मेमोइज़ करता है: useMemo(() => computeExpensive(a, b), [a, b]) गणना किया गया मान लौटाता है, न कि फ़ंक्शन।
तकनीकी रूप से, useCallback, useMemo के ऊपर सिंटैक्टिक शुगर है: useCallback(fn, deps), useMemo(() => fn, deps) के समतुल्य है। यह सिंटैक्स केवल पठनीयता के लिए मौजूद है — ताकि डेवलपर स्पष्ट रूप से देख सके कि एक फ़ंक्शन मेमोइज़ किया जा रहा है, न कि कोई मान। useCallback और फ़ंक्शन के साथ useMemo के बीच प्रदर्शन में कोई अंतर नहीं है — वे समान कोड उत्पन्न करते हैं।
| हुक | मेमोइज़ करता है | सिंटैक्स | उपयोग |
|---|---|---|---|
| useCallback | फ़ंक्शन (रेफरेंस) | useCallback(fn, deps) | चाइल्ड कंपोनेंट्स के लिए कॉलबैक |
| useMemo | गणना परिणाम | useMemo(() => value, deps) | महँगी गणनाएँ, ऑब्जेक्ट मेमोइज़ेशन |
// ये समतुल्य हैं:
const handleClick = useCallback(() => doSomething(a, b), [a, b]);
const handleClick = useMemo(() => () => doSomething(a, b), [a, b]);
सबसे आम गलती चाइल्ड कंपोनेंट्स पर React.memo के बिना सभी फ़ंक्शनों को useCallback में अर्थहीन रूप से लपेटना है। यदि चाइल्ड कंपोनेंट React.memo में लिपटा नहीं है, तो वह हर पैरेंट रेंडर पर फिर भी री-रेंडर करेगा, भले ही कॉलबैक रेफरेंस बदले या नहीं। React.memo के बिना useCallback — लागत बिना लाभ के।
// ❌ बेकार: चाइल्ड पर React.memo नहीं
const handle = useCallback(() => doStuff(), []);
<Child onClick={handle} />; // Child React.memo के बिना फिर भी री-रेंडर करता है
// ❌ स्टेल क्लोज़र: निर्भरता गायब
const handle = useCallback(() => {
console.log(count); // count हमेशा 0 है — स्टेल क्लोज़र!
}, []);
// ✅ सही: निर्भरताएँ शामिल करें
const handle = useCallback(() => {
console.log(count);
}, [count]);
useCallback में स्टेल क्लोज़र की समस्या निर्भरता ऐरे में सभी उपयोग किए गए वेरिएबल्स को शामिल करके हल की जाती है। exhaustive-deps के साथ eslint-plugin-react-hooks स्वचालित रूप से जाँच करता है कि कॉलबैक बॉडी के सभी वेरिएबल ऐरे में मौजूद हैं। यदि कॉलबैक setState का उपयोग करता है, जो रेंडरों के बीच नहीं बदलता, तो इसे सुरक्षित रूप से deps में शामिल किया जा सकता है — React setState की स्थिरता की गारंटी देता है।
अक्सर पूछे जाने वाले प्रश्न
नहीं। useCallback केवल तीन मामलों में समझ में आता है: चाइल्ड कंपोनेंट React.memo में लिपटा है, फ़ंक्शन useEffect निर्भरता ऐरे में उपयोग किया गया है, या फ़ंक्शन किसी कस्टम हुक में पास किया गया है जो रेफरेंस समानता पर निर्भर करता है। अन्य मामलों में, useCallback बिना लाभ के ओवरहेड जोड़ता है। React टीम पहले ऑप्टिमाइज़ेशन के बिना लिखने और प्रोफाइलिंग परिणामों के आधार पर उन्हें जोड़ने की सलाह देती है।
सरल कंपोनेंट्स के लिए — हर रेंडर पर नया फ़ंक्शन थोड़ा तेज़ है, क्योंकि useCallback निर्भरता तुलना और ऐरे आवंटन पर संसाधन खर्च करता है। गहरे React.memo ट्री वाले कंपोनेंट्स के लिए, useCallback हजारों चाइल्ड तत्वों के री-रेंडर को रोककर बेहतर है। अनुमान लगाने के बजाय मापें और तुलना करें — वस्तुनिष्ठ मूल्यांकन के लिए React DevTools Profiler का उपयोग करें।
हाँ, useCallback async फ़ंक्शन के साथ ठीक वैसे ही काम करता है जैसे सिंक्रोनस फ़ंक्शन के साथ। हुक फ़ंक्शन को ही मेमोइज़ करता है, और परिणाम (Promise) हर बार कॉल करने पर लौटाया जाता है। useCallback के अंदर async फ़ंक्शन useEffect में उपयोग किए जाने वाले स्थिर डेटा लोडिंग कॉलबैक के लिए एक सामान्य पैटर्न है: const fetchData = useCallback(async (id) => {...}, [])।
React DevTools Profiler का उपयोग करें — यह दिखाता है कि कौन से कंपोनेंट री-रेंडर करते हैं और क्यों। प्रोग्रामेटिक जाँच के लिए, console.log जोड़ें या useWhyDidYouUpdate का उपयोग करें — एक लाइब्रेरी जो री-रेंडर का कारण लॉग करती है। मुख्य कारण: प्रॉप बदला (कॉलबैक रेफरेंस सहित), स्टेट बदला, या कॉन्टेक्स्ट बदला। यदि useCallback मदद नहीं करता — जाँचें कि सभी निर्भरताएँ सही ढंग से निर्दिष्ट हैं।
React.memo के बिना भी, useCallback कॉन्टेक्स्ट वैल्यू के लिए useMemo के साथ उपयोगी हो सकता है। यदि आप Context.Provider में फ़ंक्शन वाला ऑब्जेक्ट पास कर रहे हैं, तो ऑब्जेक्ट निर्माण को useMemo में और प्रत्येक फ़ंक्शन को useCallback में लपेटें। यह किसी एक फ़ंक्शन के बदलने पर सभी कॉन्टेक्स्ट उपभोक्ताओं के री-रेंडर को रोकता है। लेकिन React.memo के बिना प्रॉप्स में सीधे कॉलबैक पास करने पर useCallback का कोई लाभ नहीं है।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें