
React useMemo vs useCallback in Hindi: इस गाइड में hooks के अंतर, optimization और performance tuning को आसान हिंदी में समझें।
दोस्तों, क्या आपके React components बार-बार फालतू में re-render हो रहे हैं? आपने performance बढ़ाने के लिए useMemo और useCallback के बारे में सुना तो होगा, लेकिन अक्सर डेवलपर्स इन दोनों के बीच कन्फ्यूज हो जाते हैं कि कब कौन सा Hook इस्तेमाल करना है। मेरे 50 साल के प्रोग्रामिंग अनुभव (और React के बचपन से इसे देखने के नाते) में मैंने देखा है कि डेवलपर्स बिना सोचे-समझे इन्हें हर जगह लगा देते हैं, जिससे कोड बेहतर होने के बजाय और धीमा हो जाता है। आज हम और आप साथ मिलकर इस उलझन को हमेशा के लिए खत्म करेंगे।
⚡ Quick Answer: React में useMemo किसी expensive calculation के value (result) को memoize (cache) करता है, जबकि useCallback पूरे function definition (reference) को memoize करता है ताकि फालतू re-renders को रोका जा सके। useMemo value लौटाता है और useCallback function लौटाता है।
---
React rendering कैसे काम करती है और Performance की समस्या कहाँ आती है?
दोस्तों, सबसे पहले हमें यह समझना होगा कि React पर्दे के पीछे काम कैसे करता है। जब भी किसी component का State या Props बदलता है, तो React उस पूरे component को फिर से render करता है। इसका मतलब है कि उस component के अंदर लिखे गए सभी variables और functions दोबारा से मेमोरी में क्रिएट होते हैं।
अब जावास्क्रिप्ट (JavaScript) के एक बेसिक नियम को याद कीजिए - Reference Equality।
// JavaScript Reference Check
const functionOne = () => console.log("Hello");
const functionTwo = () => console.log("Hello");
console.log(functionOne === functionTwo); // Output: false
भले ही दोनों functions बिल्कुल एक जैसे दिखते हैं, लेकिन मेमोरी में उनका एड्रेस अलग-अलग होता है। इसलिए, जब भी आपका component re-render होता है, तो उसके अंदर घोषित किए गए पुराने functions और objects डिलीट हो जाते हैं और नए memory reference के साथ नए बन जाते हैं।
ध्यान देने वाली बात ये है कि अगर आप इन functions को किसी Child Component में props के रूप में भेज रहे हैं, तो Child Component को लगेगा कि उसे नया prop मिला है, और वह भी बिना किसी कारण दोबारा render (re-render) हो जाएगा। इसी फालतू re-rendering को रोकने के लिए React हमें दो अस्त्र देता है: useMemo और useCallback।
---
useMemo Hook क्या है और यह कैसे काम करता है?
सरल शब्दों में कहें तो, useMemo का काम है किसी भारी-भरकम (expensive) calculation के परिणाम को याद रखना (Cache करना)। यह तभी दोबारा कैलकुलेट करेगा जब उसके Dependencies बदलेंगे।
मान लीजिए आपके पास एक ऐसा फ़ंक्शन है जो 10 लाख डेटा रिकॉर्ड्स को फ़िल्टर करता है। अगर आप इसे सामान्य रूप से लिखेंगे, तो हर छोटे-से-छोटे render (जैसे कि कोई UI toggle button दबाने पर) पर वह 10 लाख रिकॉर्ड्स वाला लूप दोबारा चलेगा, जिससे आपका ऐप लैग (lag) करने लगेगा।
useMemo का Syntax:
const memoizedValue = useMemo(() => {
return computeExpensiveValue(a, b);
}, [a, b]);
यहाँ useMemo पहले पैरामीटर के रूप में एक फ़ंक्शन लेता है जो वैल्यू रिटर्न करता है, और दूसरे पैरामीटर के रूप में dependencies की array लेता है। जब तक a या b की वैल्यू नहीं बदलेगी, तब तक React पिछली सेव की हुई वैल्यू को ही डायरेक्ट इस्तेमाल करेगा, फ़ंक्शन को दोबारा रन नहीं करेगा।
---
useCallback Hook क्या है और इसकी जरूरत क्यों पड़ती है?
अब बात करते हैं useCallback की। जहाँ useMemo किसी वैल्यू (जैसे array, object, number, string) को सेव करता है, वहीं useCallback पूरे के पूरे फ़ंक्शन के रेफरेंस (Function Reference) को ही मेमोरी में लॉक कर देता है।
यह तब बहुत काम आता है जब आप किसी Callback Function को किसी ऐसे Child Component में पास करते हैं जिसे आपने React.memo से ऑप्टिमाइज़ किया हुआ है।
useCallback का Syntax:
const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);
ध्यान दें: useCallback(fn, deps) असल में useMemo(() => fn, deps) के बिल्कुल बराबर है। यह केवल एक syntactical sugar है ताकि आपको फ़ंक्शन रिटर्न करने के लिए एक्स्ट्रा फ़ंक्शन रैपर न लिखना पड़े।
---
React useMemo vs useCallback में मुख्य अंतर क्या है? (Comparison Table)
चलो दोस्तों, इन दोनों के बीच के अंतर को एक साफ़-सुथरी टेबल के ज़रिए समझते हैं ताकि इंटरव्यू में भी आप इसका सॉलिड जवाब दे सकें:
| Feature / Parameter | useMemo Hook | useCallback Hook |
|---|---|---|
| मुख्य उद्देश्य (Purpose) | Expensive Calculation के Output Value को कैश करना। | Function की definition/reference को री-क्रिएट होने से बचाना। |
| क्या रिटर्न करता है? (Returns) | फ़ंक्शन के एक्ज़ीक्यूशन का Result (Value). | वह खुद Executable Function का reference. |
| कब यूज़ करें? (When to use) | जब heavy calculations (जैसे sorting, filtering) करनी हों। | जब child component को callback props पास करने हों ताकि री-रेंडर न हो। |
| Syntax Example | useMemo(() => value, [deps]) |
useCallback(() => { ... }, [deps]) |
---
Architecture Flow: Memory में Value vs Function Cache कैसे होता है?
इस आर्किटेक्चरल डायग्राम को देखकर आपको समझ आएगा कि रेंडरिंग के समय React का इंजन इन दोनों हुक्स के साथ कैसा व्यवहार करता है:
🏗️ React Memoization Architecture Flow
State Trigger
→
useMemo: Returns Cached VALUE
|
useCallback: Returns Cached FUNCTION
Diagram: rendering के दौरान फालतू recalculation और नए function instances को रोकना।
---
Production-Ready Code Example: चलिए दोनों Hooks को एक साथ लाइव समझते हैं
अब थ्योरी तो बहुत हो गई, चलिए एक रियल-वर्ल्ड प्रोडक्शन-रेडी कोड उदाहरण देखते हैं। इस उदाहरण में हमारे पास एक प्रोडक्ट लिस्ट है जिसे हम फ़िल्टर करेंगे (useMemo का उपयोग करके) और एक डिलीट एक्शन है जो हम चाइल्ड कंपोनेंट में पास करेंगे (useCallback का उपयोग करके)।
यहाँ हम React.memo का भी उपयोग करेंगे ताकि आप लाइव देख सकें कि कैसे कंपोनेंट का री-रेंडर रुकता है।
import React, { useState, useMemo, useCallback } from 'react';
// यह एक चाइल्ड कंपोनेंट है जिसे हम React.memo में रैप कर रहे हैं।
// यह केवल तभी दोबारा रेंडर होगा जब इसके props (onDelete या item) बदलेंगे।
const ProductItem = React.memo(({ item, onDelete }) => {
console.log(`ProductItem Renders: ${item.name}`);
return (
{item.name} - ₹{item.price}
onDelete(item.id)}
style={{ backgroundColor: '#ef4444', color: 'white', border: 'none', padding: '5px 10px', cursor: 'pointer' }}
>
Delete
);
});
// मुख्य पैरेंट कंपोनेंट
export default function ProductDashboard() {
const [products, setProducts] = useState([
{ id: 1, name: 'Samsung Galaxy S23', price: 74999 },
{ id: 2, name: 'Apple iPhone 15', price: 79999 },
{ id: 3, name: 'OnePlus 11R', price: 39999 },
{ id: 4, name: 'Google Pixel 8', price: 75999 },
]);
const [filterText, setFilterText] = useState('');
const [themeDark, setThemeDark] = useState(false);
// 1. useMemo का उपयोग: जब थीम टॉगल होगी, तब फ़िल्टरिंग दोबारा नहीं चलेगी।
// फ़िल्टर तभी चलेगा जब 'products' या 'filterText' में बदलाव होगा।
const filteredProducts = useMemo(() => {
console.log("Filtering products calculation running...");
return products.filter(product =>
product.name.toLowerCase().includes(filterText.toLowerCase())
);
}, [products, filterText]);
// 2. useCallback का उपयोग: यह सुनिश्चित करता है कि onDelete का रेफरेंस न बदले।
// अगर हम यहाँ useCallback न लगाएं, तो 'themeDark' बदलने पर भी onDelete नया बन जाएगा,
// जिससे ProductItem (चाइल्ड) फालतू में री-रेंडर होगा।
const handleDelete = useCallback((id) => {
setProducts((prevProducts) => prevProducts.filter(p => p.id !== id));
}, []); // खाली डिपेंडेंसी क्योंकि setProducts का स्टेट अपडेशन फंक्शन सेफ है
return (
# 📱 Product Dashboard (React Performance Optimization)
setThemeDark(!themeDark)}
style={{ padding: '8px 16px', cursor: 'pointer', marginRight: '10px' }}
>
Toggle Dark Mode ({themeDark ? "ON" : "OFF"})
setFilterText(e.target.value)}
style={{ padding: '8px', width: '250px' }}
/>
### Products List
{filteredProducts.length > 0 ? (
filteredProducts.map(product => (
))
) : (
No products match your search query!
)}
);
}
इस कोड में क्या खास है? (Step-by-Step Analysis):
-
Theme Toggle Test: जब आप "Toggle Dark Mode" बटन पर क्लिक करते हैं, तो ऐप का थीम स्टेट बदलता है। लेकिन ध्यान से देखें, console में "Filtering products calculation running..." प्रिंट नहीं होगा। ऐसा इसलिए क्योंकि
useMemoने फ़िल्टर किए हुए परिणाम को कैश कर लिया है। -
React.memo integration:
ProductItemकंपोनेंटReact.memoसे सुरक्षित है। जब थीम बदलती है, तोhandleDeleteफ़ंक्शन का मेमोरी रेफरेंसuseCallbackके कारण वही रहता है। नतीजतन, कोई भीProductItemदोबारा रेंडर नहीं होता।
---
Common Errors और Debugging: डेवलपर्स कहाँ गलती करते हैं?
दोस्तों, बड़े प्रोजेक्ट्स में काम करते हुए कई बार कोडर्स ऐसी गलतियाँ कर बैठते हैं जिससे ऐप क्रैश या स्लो हो जाता है। यहाँ कुछ मुख्य गलतियों और उनके समाधान (solution to fix error) दिए गए हैं:
1. Missing Dependencies in Dependency Array
यह सबसे आम error है। यदि आप dependency array में वह variable लिखना भूल जाते हैं जिसका उपयोग आपने Hook के अंदर किया है, तो Hook हमेशा पुरानी (stale) वैल्यू का उपयोग करेगा। इसे Stale Closure कहते हैं।
// ❌ गलत तरीका (Stale Closure Issue)
const logValue = useCallback(() => {
console.log(count); // 'count' हमेशा पुराना ही रहेगा क्योंकि dependency array खाली है!
}, []);
// सही तरीका
const logValue = useCallback(() => {
console.log(count);
}, [count]);
2. Over-optimizing / Premature Optimization
हर साधारण फ़ंक्शन या वैल्यू पर useCallback या useMemo लगाने की गलती बिल्कुल न करें। इन Hooks को मेमोरी में स्टोर करने और डिपेंडेंसी चेक करने की भी अपनी एक ओवरहेड कॉस्ट (Performance Cost) होती है।
अगर आपका फ़ंक्शन बहुत छोटा है (जैसे कि सिर्फ़ एक स्टेट को सेट करना) और वह किसी जटिल चाइल्ड कंपोनेंट में पास नहीं हो रहा है, तो सामान्य फ़ंक्शन का ही उपयोग करें।
---
Best Practices: Performance Optimization कब करना चाहिए और कब नहीं?
मेरे 50 साल के तजुर्बे की बात याद रखना दोस्तों - "Optimization is good, but premature optimization is root of all evil in coding." चलिए इसे आसान नियमों में बाँटते हैं:
-
useMemo का उपयोग तब करें जब:
- आप कोई भारी लूप चला रहे हैं (जैसे 1000+ आइटम्स को सॉर्ट, मैप या फ़िल्टर करना)।
- आप किसी जटिल mathematical calculations (जैसे फ़ैक्टोरियल, ग्राफ नोड्स आदि) का परिणाम स्टोर कर रहे हैं।
- आप किसी ऑब्जेक्ट/एरे को दूसरे कस्टम हुक के डिपेंडेंसी के रूप में पास कर रहे हैं।
-
useCallback का उपयोग तब करें जब:
- आप किसी callback फ़ंक्शन को
React.memoवाले Child Component में प्रोप के रूप में भेज रहे हैं। - वह फ़ंक्शन किसी अन्य custom hook या
useEffectकी dependency array में शामिल हो।
- आप किसी callback फ़ंक्शन को
-
इस्तेमाल कब न करें?
- साधारण क्लिक हैंडलर्स जैसे
const handleClick = () => alert('Hi')पर ये हुक्स लगाने का कोई फायदा नहीं है। - जब पैरेंट री-रेंडर होने पर चाइल्ड कंपोनेंट का भी रेंडर होना लाज़मी हो और उसे रोका न जा सके।
- साधारण क्लिक हैंडलर्स जैसे
अगर आप इसके बारे में और भी गहराई से जानना चाहते हैं, तो React Official Documentation पर जाकर हुक्स के डिज़ाइन प्रिंसिपल्स पढ़ सकते हैं।
---
तो दोस्तों, हमने आज विस्तार से सीखा कि useMemo और useCallback का सही उपयोग कैसे किया जाता है और इनके बीच का बारीक अंतर क्या है। उम्मीद है अब आपके रिएक्ट ऐप्स सुपर-फ़ास्ट चलेंगे और फ़ालतू री-रेंडर्स बंद हो जाएंगे। अपने अगले कोड में इसका प्रयोग ज़रूर करके देखें और कोई भी समस्या हो तो बेझिझक पूछें!
---
Frequently Asked Questions (FAQs)
Q1: क्या useMemo और useCallback का अधिक उपयोग करने से ऐप धीमा हो सकता है?
हाँ, बिल्कुल! हर Hook को री-रेंडर के समय डिपेंडेंसी ऐरे के तत्वों की तुलना करनी पड़ती है, जिसमें CPU टाइम खर्च होता है। साथ ही, इनके कारण मेमोरी ओवरहेड बढ़ता है। केवल भारी कैलकुलेशन या भारी कंपोनेंट री-रेंडर्स को रोकने के लिए ही इनका उपयोग करें।
Q2: क्या useCallback के बिना React.memo काम करेगा?
यदि आप चाइल्ड कंपोनेंट में कोई फ़ंक्शन प्रोप के रूप में भेज रहे हैं और उसे useCallback से नहीं लपेटते, तो पैरेंट के री-रेंडर होने पर नया फ़ंक्शन रेफरेंस जनरेट होगा। इस कारण React.memo प्रोप्स में बदलाव समझकर चाइल्ड को दोबारा रेंडर कर देगा। इसलिए इन दोनों का तालमेल ज़रूरी है।
Q3: React compiler (React Forget) के आने के बाद क्या हमें इन Hooks की ज़रूरत होगी?
भविष्य में आने वाला React Compiler खुद-ब-खुद कोड को ऑप्टिमाइज़ कर देगा, जिससे कई मामलों में useMemo और useCallback को मैन्युअली लिखने की ज़रूरत नहीं पड़ेगी। लेकिन पुराने कोडबेस को संभालने और React के अंतर्निहित व्यवहार को समझने के लिए आज भी इनका गहरा ज्ञान आवश्यक है।
Q4: क्या Dependency Array में खाली ऐरे [] डालने से क्या होता है?
खाली ऐरे [] डालने से React को यह संकेत मिलता है कि यह वैल्यू या फ़ंक्शन केवल component के माउंट (initial render) होते समय ही कैलकुलेट या इनिशियलाइज़ होना चाहिए और उसके बाद कभी भी दोबारा चेंज नहीं होना चाहिए।
Q5: क्या React Context API के साथ useMemo का उपयोग किया जा सकता है?
हाँ, Context API में value ऑब्जेक्ट को useMemo के अंदर रैप करना एक बहुत ही बेहतरीन प्रैक्टिस है। इससे कॉन्टेक्स्ट का उपभोग (consume) करने वाले कंपोनेंट्स अनावश्यक री-रेंडरिंग से बच जाते हैं जब तक कि सचमुच कॉन्टेक्स्ट स्टेट में बदलाव न हो।
Top comments (0)