DEV Community

banti kevat
banti kevat

Posted on • Originally published at itinfohubs.blogspot.com

React useMemo vs useCallback Difference

React useMemo vs useCallback Difference (in Hindi)
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

Enter fullscreen mode Exit fullscreen mode

भले ही दोनों 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]);

Enter fullscreen mode Exit fullscreen mode

यहाँ 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]);

Enter fullscreen mode Exit fullscreen mode

ध्यान दें: 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!


        )}


  );
}

Enter fullscreen mode Exit fullscreen mode

इस कोड में क्या खास है? (Step-by-Step Analysis):

  1. Theme Toggle Test: जब आप "Toggle Dark Mode" बटन पर क्लिक करते हैं, तो ऐप का थीम स्टेट बदलता है। लेकिन ध्यान से देखें, console में "Filtering products calculation running..." प्रिंट नहीं होगा। ऐसा इसलिए क्योंकि useMemo ने फ़िल्टर किए हुए परिणाम को कैश कर लिया है।
  2. 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]); 

Enter fullscreen mode Exit fullscreen mode

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 में शामिल हो।
  • इस्तेमाल कब न करें?
    • साधारण क्लिक हैंडलर्स जैसे 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)