React चा useCallback हुक शिका. फंक्शन मेमोरायझेशन म्हणजे काय, ते कधी वापरावे (आणि कधी नाही), आणि तुमच्या घटकांना (components) कार्यक्षमतेसाठी कसे अनुकूल करावे हे जाणून घ्या.
React useCallback: फंक्शन मेमोरायझेशन आणि परफॉर्मन्स ऑप्टिमायझेशनमध्ये सखोल माहिती
आधुनिक वेब डेव्हलपमेंटच्या जगात, React त्याच्या डिक्लेरेटिव्ह UI आणि कार्यक्षम रेंडरिंग मॉडेलमुळे वेगळे ठरते. तथापि, ॲप्लिकेशन्सची (applications) जटिलता वाढत असताना, इष्टतम कार्यक्षमता सुनिश्चित करणे हे प्रत्येक डेव्हलपरसाठी एक महत्त्वाचे कर्तव्य बनते. React या आव्हानांना सामोरे जाण्यासाठी शक्तिशाली साधनांचा संच प्रदान करते, आणि त्यापैकी सर्वात महत्त्वाचे—आणि अनेकदा गैरसमज झालेले—ऑप्टिमायझेशन हुक्स आहेत. आज, आपण त्यापैकी एकाचा सखोल अभ्यास करणार आहोत: useCallback.
हे सर्वसमावेशक मार्गदर्शक useCallback हुकला सोपे करेल. JavaScript ची मूलभूत संकल्पना जी त्याला आवश्यक बनवते, त्याची सिंटॅक्स आणि कार्यपद्धती आपण समजून घेऊ, आणि सर्वात महत्त्वाचे म्हणजे, आपल्या कोडमध्ये ते कधी वापरावे—आणि कधी नाही—याबद्दल स्पष्ट मार्गदर्शक तत्त्वे स्थापित करू. या मार्गदर्शकाच्या शेवटी, आपण useCallback ला जादूची काठी म्हणून नव्हे, तर आपल्या React ॲप्लिकेशन्सना अधिक वेगवान आणि कार्यक्षम बनवण्यासाठी एक अचूक साधन म्हणून वापरण्यास सुसज्ज असाल.
मूळ समस्या: रेफरेंशियल इक्वलिटी समजून घेणे
useCallback काय करते हे समजून घेण्यापूर्वी, आपल्याला JavaScript मधील एक मूलभूत संकल्पना समजून घ्यावी लागेल: रेफरेंशियल इक्वलिटी (referential equality). JavaScript मध्ये, फंक्शन्स (functions) हे ऑब्जेक्ट्स (objects) असतात. याचा अर्थ जेव्हा तुम्ही दोन फंक्शन्सची (किंवा कोणत्याही दोन ऑब्जेक्ट्सची) तुलना करता, तेव्हा तुम्ही त्यांच्या कंटेंटची तुलना करत नसता, तर त्यांच्या रेफरन्सची—मेमरीमधील त्यांच्या विशिष्ट स्थानाची तुलना करत असता.
हा साधा JavaScript स्निपेट विचारात घ्या:
const func1 = () => { console.log('Hello'); };
const func2 = () => { console.log('Hello'); };
console.log(func1 === func2); // Outputs: false
func1 आणि func2 मध्ये सारखाच कोड असला तरी, ते दोन वेगळे फंक्शन ऑब्जेक्ट्स आहेत जे वेगवेगळ्या मेमरी ॲड्रेसवर तयार केले गेले आहेत. त्यामुळे, ते समान नाहीत.
हे React कंपोनंट्सना कसे प्रभावित करते
एक React फंक्शनल कंपोनंट (functional component) मूलतः एक फंक्शन आहे जो प्रत्येक वेळी कंपोनंटला रेंडर करण्याची आवश्यकता असते तेव्हा चालतो. हे तेव्हा घडते जेव्हा त्याची स्टेट (state) बदलते, किंवा जेव्हा त्याचा पॅरेंट कंपोनंट (parent component) पुन्हा रेंडर (re-render) होतो. जेव्हा हे फंक्शन चालते, तेव्हा त्यातील सर्व काही, व्हेरिएबल (variable) आणि फंक्शन डिक्लेरेशन (function declarations) सह, नव्याने तयार होते.
चला एक सामान्य कंपोनंट पाहूया:
import React, { useState } from 'react';
const Counter = () => {
const [count, setCount] = useState(0);
// This function is re-created on every single render
const handleIncrement = () => {
console.log('Creating a new handleIncrement function');
setCount(count + 1);
};
return (
Count: {count}
);
};
प्रत्येक वेळी तुम्ही "Increment" बटणावर क्लिक करता, तेव्हा count स्टेट बदलते, ज्यामुळे Counter कंपोनंट पुन्हा रेंडर होतो. प्रत्येक री-रेंडरिंग दरम्यान, एक अगदी नवीन handleIncrement फंक्शन तयार होते. अशा साध्या कंपोनंटसाठी, कार्यक्षमतेवरील परिणाम नगण्य असतो. JavaScript इंजिन फंशन्स तयार करण्यात अत्यंत वेगवान आहे. मग, आपल्याला याची काळजी करण्याची गरज का आहे?
फंक्शन्स पुन्हा तयार करणे समस्या का बनते
समस्या फंक्शन तयार करण्यात नाही; ती चेन रिॲक्शनमध्ये आहे जी फंक्शनला चाइल्ड कंपोनंट्सना (child components) प्रॉप (prop) म्हणून पास केल्यावर होऊ शकते, विशेषतः React.memo सह ऑप्टिमाइज केलेल्या कंपोनंट्समध्ये.
React.memo एक हायर-ऑर्डर कंपोनंट (HOC) आहे जो कंपोनंटला मेमोराइज करतो. तो कंपोनंटच्या प्रॉप्सची (props) शॅलो कम्पेरिजन (shallow comparison) करून काम करतो. जर नवीन प्रॉप्स जुन्या प्रॉप्ससारखेच असतील, तर React कंपोनंटला पुन्हा रेंडर करणे वगळेल आणि शेवटचा रेंडर केलेला रिझल्ट पुन्हा वापरेल. अनावश्यक रेंडर सायकल (render cycles) टाळण्यासाठी हे एक शक्तिशाली ऑप्टिमायझेशन आहे.
आता, रेफरेंशियल इक्वलिटीची (referential equality) आपली समस्या कुठे येते ते पाहूया. कल्पना करा की आपल्याकडे एक पॅरेंट कंपोनंट (parent component) आहे जो एका मेमोराइज्ड चाइल्ड कंपोनंटला हँडलर फंक्शन पास करतो.
import React, { useState } from 'react';
// A memoized child component that only re-renders if its props change.
const MemoizedButton = React.memo(({ onIncrement }) => {
console.log('MemoizedButton is rendering!');
return <button onClick={onIncrement}>Increment from Child</button>;
});
const ParentComponent = () => {
const [count, setCount] = useState(0);
const [otherState, setOtherState] = useState(false);
// This function is re-created every time ParentComponent renders
const handleIncrement = () => {
setCount(count + 1);
};
return (
<div>
<p>Parent Count: {count}</p>
<p>Other State: {String(otherState)}</p>
<button onClick={() => setOtherState(!otherState)}>Toggle Other State</button>
<hr />
<MemoizedButton onIncrement={handleIncrement} />
</div>
);
};
या उदाहरणात, MemoizedButton ला एक प्रॉप (prop) मिळते: onIncrement. जेव्हा तुम्ही "Toggle Other State" बटणावर क्लिक करता, तेव्हा फक्त ParentComponent पुन्हा रेंडर होतो अशी तुमची अपेक्षा असू शकते कारण count बदललेला नाही, आणि त्यामुळे onIncrement फंक्शन तार्किकदृष्ट्या समान आहे. तथापि, जर तुम्ही हा कोड चालवला, तर "Toggle Other State" वर प्रत्येक वेळी क्लिक केल्यावर तुम्हाला कन्सोलमध्ये "MemoizedButton is rendering!" दिसेल.
असे का होते?
जेव्हा ParentComponent पुन्हा रेंडर होतो (setOtherState मुळे), तेव्हा तो handleIncrement फंक्शनची नवीन इन्स्टन्स (new instance) तयार करतो. जेव्हा React.memo MemoizedButton साठी प्रॉप्सची तुलना करते, तेव्हा ते पाहते की oldProps.onIncrement !== newProps.onIncrement कारण रेफरेंशियल इक्वलिटीमुळे (referential equality). नवीन फंक्शन वेगळ्या मेमरी ॲड्रेसवर (memory address) आहे. या अयशस्वी तपासणीमुळे आपल्या मेमोराइज्ड चाइल्डला पुन्हा रेंडर होण्यास भाग पाडले जाते, ज्यामुळे React.memo चा उद्देश पूर्णपणे निष्फळ ठरतो.
ही प्राथमिक परिस्थिती आहे जिथे useCallback मदतीला येते.
उपाय: मेमोरायझिंग सह `useCallback`
useCallback हुक नेमकी हीच समस्या सोडवण्यासाठी डिझाइन केलेला आहे. हे तुम्हाला रेंडरिंग दरम्यान फंक्शनची व्याख्या मेमोराइज (memoize) करण्याची परवानगी देते, ज्यामुळे त्याच्या डिपेंडन्सीज (dependencies) बदलल्याशिवाय ते रेफरेंशियल इक्वलिटी (referential equality) राखते याची खात्री होते.
सिंटॅक्स
const memoizedCallback = useCallback(
() => {
// The function to memoize
doSomething(a, b);
},
[a, b], // The dependency array
);
- पहिले आर्ग्युमेंट: तुम्हाला मेमोराइज करायचे असलेले इनलाइन कॉलबॅक फंक्शन.
- दुसरे आर्ग्युमेंट: एक डिपेंडन्सी ॲरे (dependency array). या ॲरेमधील मूल्यांपैकी (values) एक मूल्य मागील रेंडरपासून (render) बदलले असेल तरच
useCallbackएक नवीन फंक्शन परत करेल.
चला आपले मागील उदाहरण useCallback वापरून रिफॅक्टर (refactor) करूया:
import React, { useState, useCallback } from 'react';
const MemoizedButton = React.memo(({ onIncrement }) => {
console.log('MemoizedButton is rendering!');
return <button onClick={onIncrement}>Increment from Child</button>;
});
const ParentComponent = () => {
const [count, setCount] = useState(0);
const [otherState, setOtherState] = useState(false);
// Now, this function is memoized!
const handleIncrement = useCallback(() => {
setCount(count + 1);
}, [count]); // Dependency: 'count'
return (
<div>
<p>Parent Count: {count}</p>
<p>Other State: {String(otherState)}</p>
<button onClick={() => setOtherState(!otherState)}>Toggle Other State</button>
<hr />
<MemoizedButton onIncrement={handleIncrement} />
</div>
);
};
आता, जेव्हा तुम्ही "Toggle Other State" वर क्लिक करता, तेव्हा ParentComponent पुन्हा रेंडर होतो. React useCallback हुक चालवतो. तो त्याच्या डिपेंडन्सी ॲरेमधील count च्या मूल्याची मागील रेंडरमधील मूल्याशी तुलना करतो. count बदललेला नसल्यामुळे, useCallback त्याने मागील वेळी परत केलेला अगदी तोच फंक्शन इन्स्टन्स (exact same function instance) परत करतो. जेव्हा React.memo MemoizedButton साठी प्रॉप्सची तुलना करते, तेव्हा ते oldProps.onIncrement === newProps.onIncrement असे आढळते. तपासणी यशस्वी होते, आणि चाइल्डचा अनावश्यक री-रेंडर यशस्वीरित्या वगळला जातो! समस्या सुटली.
डिपेंडन्सी ॲरेमध्ये प्रभुत्व मिळवणे
डिपेंडन्सी ॲरे (dependency array) useCallback योग्यरित्या वापरण्याचा सर्वात महत्त्वाचा भाग आहे. तो React ला फंक्शन कधी पुन्हा तयार करणे सुरक्षित आहे हे सांगतो. यात चूक केल्यास असे सूक्ष्म बग्स (bugs) होऊ शकतात जे शोधणे कठीण आहे.
रिकामी ॲरे: `[]`
जर तुम्ही रिकामी डिपेंडन्सी ॲरे दिली, तर तुम्ही React ला सांगत आहात: "हे फंक्शन पुन्हा तयार करण्याची कधीही गरज नाही. सुरुवातीच्या रेंडरमधील (render) आवृत्ती कायमची चांगली आहे."
const stableFunction = useCallback(() => {
console.log('This will always be the same function');
}, []); // Empty array
हे एक अत्यंत स्थिर रेफरन्स तयार करते, परंतु त्यात एक मोठी कमतरता आहे: "स्टेल क्लोजर" (stale closure) समस्या. क्लोजर म्हणजे जेव्हा एखादे फंक्शन ज्या स्कोपमध्ये (scope) ते तयार केले गेले होते त्या स्कोपमधील व्हेरिएबल्स (variables) "लक्षात ठेवते". जर तुमचा कॉलबॅक स्टेट (state) किंवा प्रॉप्स (props) वापरत असेल परंतु तुम्ही त्यांना डिपेंडन्सी म्हणून सूचीबद्ध करत नसाल, तर तो त्यांच्या सुरुवातीच्या मूल्यांवर क्लोजिंग करेल.
स्टेल क्लोजरचे उदाहरण:
const StaleCounter = () => {
const [count, setCount] = useState(0);
const handleLogCount = useCallback(() => {
// This 'count' is the value from the initial render (0)
// because `count` is not in the dependency array.
console.log(`Current count is: ${count}`);
}, []); // WRONG! Missing dependency
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
<button onClick={handleLogCount}>Log Count</button>
</div>
);
};
या उदाहरणात, तुम्ही "Increment" वर कितीही वेळा क्लिक केले तरी, "Log Count" वर क्लिक केल्यावर नेहमी "Current count is: 0" असे प्रिंट होईल. handleLogCount फंक्शन पहिल्या रेंडरमधील count च्या मूल्याला चिकटून राहते कारण त्याचा डिपेंडन्सी ॲरे रिकामा आहे.
योग्य ॲरे: `[dep1, dep2, ...]`
स्टेल क्लोजरची समस्या सोडवण्यासाठी, तुम्ही तुमच्या फंक्शनने वापरलेल्या कंपोनंट स्कोपमधील (state, props, इत्यादी) प्रत्येक व्हेरिएबलला डिपेंडन्सी ॲरेमध्ये समाविष्ट करणे आवश्यक आहे.
const handleLogCount = useCallback(() => {
console.log(`Current count is: ${count}`);
}, [count]); // CORRECT! Now it depends on count.
आता, जेव्हा जेव्हा count बदलेल, तेव्हा useCallback एक नवीन handleLogCount फंक्शन तयार करेल जे count च्या नवीन मूल्यावर क्लोजिंग करेल. हुक वापरण्याचा हा योग्य आणि सुरक्षित मार्ग आहे.
प्रो टीप: नेहमी eslint-plugin-react-hooks पॅकेज वापरा. हे `exhaustive-deps` नियम प्रदान करते जे तुम्हाला तुमच्या `useCallback`, `useEffect`, किंवा `useMemo` हुकमध्ये डिपेंडन्सी (dependency) चुकल्यास आपोआप चेतावणी देईल. हे एक अमूल्य सुरक्षा जाळे आहे.
ॲडव्हान्स पॅटर्न आणि तंत्रे
1. डिपेंडन्सी टाळण्यासाठी फंक्शनल अपडेट्स
काहीवेळा तुम्हाला स्टेट अपडेट (state update) करणारे एक स्थिर फंक्शन हवे असते, परंतु स्टेट प्रत्येक वेळी बदलल्यावर ते पुन्हा तयार करायचे नसते. कस्टम हुक्स (custom hooks) किंवा कॉन्टेक्स्ट प्रोव्हायडर (context providers) ला पास केलेल्या फंक्शन्ससाठी हे सामान्य आहे. स्टेट सेटरच्या (state setter) फंक्शनल अपडेट फॉर्मचा (functional update form) वापर करून तुम्ही हे साध्य करू शकता.
const handleIncrement = useCallback(() => {
// `setCount` can take a function that receives the previous state.
// This way, we don't need to depend on `count` directly.
setCount(prevCount => prevCount + 1);
}, []); // The dependency array can now be empty!
setCount(prevCount => ...) वापरल्याने, आपल्या फंक्शनला कंपोनंट स्कोपमधून (component scope) count व्हेरिएबल वाचण्याची आता गरज नाही. कारण ते कशावरही अवलंबून नाही, आपण सुरक्षितपणे एक रिकामी डिपेंडन्सी ॲरे (dependency array) वापरू शकतो, ज्यामुळे कंपोनंटच्या संपूर्ण लाइफसायकलसाठी (lifecycle) खरोखरच स्थिर फंक्शन तयार होते.
2. अस्थिर मूल्यांसाठी `useRef` वापरणे
जर तुमच्या कॉलबॅकला प्रॉप (prop) किंवा स्टेटच्या (state) नवीनतम मूल्यांमध्ये प्रवेश करण्याची आवश्यकता असेल जे खूप वारंवार बदलते, परंतु तुम्हाला तुमचा कॉलबॅक अस्थिर करायचा नसेल तर काय? तुम्ही `useRef` चा वापर नवीनतम मूल्याचा म्युटेबल रेफरन्स (mutable reference) ठेवण्यासाठी करू शकता, ज्यामुळे पुन्हा रेंडर (re-renders) ट्रिगर होणार नाहीत.
const VeryFrequentUpdates = ({ onEvent }) => {
const [value, setValue] = useState('');
// Keep a ref to the latest version of the onEvent callback
const onEventRef = useRef(onEvent);
useEffect(() => {
onEventRef.current = onEvent;
}, [onEvent]);
// This internal callback can be stable
const handleInternalAction = useCallback(() => {
// ...some internal logic...
// Call the latest version of the prop function via the ref
if (onEventRef.current) {
onEventRef.current();
}
}, []); // Stable function
// ...
};
हा एक प्रगत पॅटर्न आहे, परंतु तो डिबाउंसिंग (debouncing), थ्रॉटलिंग (throttling) किंवा स्थिर कॉलबॅक रेफरन्स (stable callback references) आवश्यक असलेल्या थर्ड-पार्टी लायब्ररींशी इंटरफेसिंग (interfacing) सारख्या जटिल परिस्थितींमध्ये उपयुक्त आहे.
महत्त्वाचा सल्ला: `useCallback` कधी वापरू नये
React हुक्समध्ये (hooks) नवीन असलेले लोक अनेकदा प्रत्येक फंक्शनला useCallback मध्ये रॅप (wrap) करण्याच्या जाळ्यात अडकतात. हे एक अँटी-पॅटर्न (anti-pattern) आहे ज्याला प्रीमेच्युअर ऑप्टिमायझेशन (premature optimization) असे म्हणतात. लक्षात ठेवा, useCallback मोफत नाही; त्याला कार्यक्षमतेचा (performance) खर्च असतो.
`useCallback` चा खर्च
- मेमरी: त्याला मेमोराइज्ड फंक्शन (memoized function) मेमरीमध्ये (memory) साठवावे लागते.
- गणन (Computation): प्रत्येक रेंडरवर (render), React ला हुकला कॉल करावा लागतो आणि डिपेंडन्सी ॲरेमधील (dependency array) आयटम्सची त्यांच्या मागील मूल्यांशी तुलना करावी लागते.
अनेक प्रकरणांमध्ये, हा खर्च लाभापेक्षा जास्त असू शकतो. हुकला कॉल करण्याचा आणि डिपेंडन्सीची तुलना करण्याचा ओव्हरहेड (overhead) फंक्शनला फक्त पुन्हा तयार करण्याच्या आणि चाइल्ड कंपोनंटला (child component) पुन्हा रेंडर होऊ देण्याच्या खर्चापेक्षा जास्त असू शकतो.
`useCallback` कधी वापरू नका:
- फंक्शन नेटिव्ह HTML एलिमेंटला पास केले असल्यास:
<div>,<button>, किंवा<input>सारख्या कंपोनंट्सना त्यांच्या इव्हेंट हँडलरसाठी (event handlers) रेफरेंशियल इक्वलिटीची (referential equality) पर्वा नसते. प्रत्येक रेंडरवरonClickला नवीन फंक्शन पास करणे पूर्णपणे ठीक आहे आणि त्याचा कार्यक्षमतेवर (performance) कोणताही परिणाम होत नाही. - प्राप्त करणारा कंपोनंट मेमोराइज्ड नसल्यास: जर तुम्ही
React.memoमध्ये रॅप केलेल्या नसलेल्या चाइल्ड कंपोनंटला कॉलबॅक पास करत असाल, तर कॉलबॅक मेमोराइज करणे निरर्थक आहे. त्याचा पॅरेंट पुन्हा रेंडर झाल्यावर चाइल्ड कंपोनंट तरीही पुन्हा रेंडर होईल. - फंक्शन एकाच कंपोनंटच्या रेंडर सायकलमध्ये (render cycle) परिभाषित आणि वापरले असल्यास: जर फंक्शन प्रॉप म्हणून पास केले नसेल किंवा दुसऱ्या हुकमध्ये (hook) डिपेंडन्सी म्हणून वापरले नसेल, तर त्याच्या रेफरन्सला मेमोराइज करण्याचे (memoize) कोणतेही कारण नाही.
// NO need for useCallback here
const handleClick = () => { console.log('Clicked!'); };
return <button onClick={handleClick}>Click Me</button>;
सुवर्ण नियम: useCallback फक्त लक्षित ऑप्टिमायझेशन (targeted optimization) म्हणून वापरा. अनावश्यकपणे पुन्हा रेंडर होत असलेल्या कंपोनंट्स ओळखण्यासाठी React DevTools Profiler वापरा. जर तुम्हाला React.memo मध्ये रॅप केलेला कंपोनंट अस्थिर कॉलबॅक प्रॉपमुळे (callback prop) अजूनही पुन्हा रेंडर होत असल्याचे आढळले, तर useCallback लागू करण्याची ती योग्य वेळ आहे.
`useCallback` विरुद्ध `useMemo`: मुख्य फरक
अनेकदा गोंधळाचा आणखी एक सामान्य मुद्दा म्हणजे useCallback आणि useMemo मधील फरक. ते खूप समान असले तरी, त्यांचे उद्देश वेगळे आहेत.
useCallback(fn, deps)फंक्शन इन्स्टन्सला (function instance) मेमोराइज (memoizes) करते. ते तुम्हाला रेंडरिंग दरम्यान समान फंक्शन ऑब्जेक्ट परत देते.useMemo(() => value, deps)फंक्शनच्या रिटर्न मूल्याला (return value) मेमोराइज करते. ते फंक्शन कार्यान्वित करते आणि तुम्हाला त्याचा परिणाम परत देते, डिपेंडन्सी (dependencies) बदलल्यास ते फक्त पुन्हा कॅल्क्युलेट (re-calculate) करते.
मूलतः, `useCallback(fn, deps)` हे `useMemo(() => fn, deps)` साठी फक्त सिंटॅक्टिक शुगर (syntactic sugar) आहे. फंशन्स मेमोराइज करण्याच्या विशिष्ट वापरासाठी हे एक सोयीचे हुक आहे.
कोणते कधी वापरावे?
- अनावश्यक री-रेंडर (re-renders) टाळण्यासाठी चाइल्ड कंपोनंट्सना (child components) पास केलेल्या फंशन्ससाठी
useCallbackवापरा (उदा.onClick,onSubmitसारखे इव्हेंट हँडलर्स). - मोठ्या डेटासेटला फिल्टर करणे, जटिल डेटा ट्रान्सफॉर्मेशन (data transformations) किंवा गणना करण्यास बराच वेळ लागणारे आणि प्रत्येक रेंडरवर पुन्हा कॅल्क्युलेट न केले जाणारे कोणतेही मूल्य यासारख्या गणनात्मकदृष्ट्या महागड्या (computationally expensive) कॅल्क्युलेशन्ससाठी
useMemoवापरा.
// Use case for useMemo: Expensive calculation
const visibleTodos = useMemo(() => {
console.log('Filtering list...'); // This is expensive
return todos.filter(t => t.status === filter);
}, [todos, filter]);
// Use case for useCallback: Stable event handler
const handleAddTodo = useCallback((text) => {
dispatch({ type: 'ADD_TODO', text });
}, []); // Stable dispatch function
return (
<TodoList todos={visibleTodos} onAdd={handleAddTodo} />
);
निष्कर्ष आणि सर्वोत्तम पद्धती
useCallback हुक (hook) तुमच्या React कार्यक्षमतेच्या ऑप्टिमायझेशन (performance optimization) टूलकिटमधील एक शक्तिशाली साधन आहे. तो थेट रेफरेंशियल इक्वलिटीची (referential equality) समस्या सोडवतो, ज्यामुळे तुम्हाला फंक्शन प्रॉप्स (function props) स्थिर करता येतात आणि `React.memo` आणि `useEffect` सारख्या इतर हुक्सची पूर्ण क्षमता अनलॉक करता येते.
मुख्य मुद्दे:
- उद्देश:
useCallbackकॉलबॅक फंक्शनची (callback function) मेमोराइज्ड (memoized) आवृत्ती परत करते जी तिच्या डिपेंडन्सीपैकी (dependencies) एक बदलल्यास बदलली जाते. - प्राथमिक वापर केस:
React.memoमध्ये रॅप केलेल्या चाइल्ड कंपोनंट्सचे (child components) अनावश्यक री-रेंडर (re-renders) टाळण्यासाठी. - दुय्यम वापर केस: इतर हुक्ससाठी, जसे की
useEffect, स्थिर फंक्शन डिपेंडन्सी (stable function dependency) प्रदान करण्यासाठी, जेणेकरून ते प्रत्येक रेंडरवर (render) चालणार नाहीत. - डिपेंडन्सी ॲरे महत्त्वाचे आहे: तुमच्या फंक्शनला अवलंबून असलेल्या सर्व कंपोनंट-स्कोप केलेल्या व्हेरिएबल्सचा (component-scoped variables) नेहमी समावेश करा. हे लागू करण्यासाठी `exhaustive-deps` ESLint नियम वापरा.
- हे एक ऑप्टिमायझेशन आहे, डीफॉल्ट नाही: प्रत्येक फंक्शनला
useCallbackमध्ये रॅप करू नका. यामुळे कार्यक्षमतेला हानी पोहोचू शकते आणि अनावश्यक जटिलता वाढू शकते. प्रथम आपल्या ॲप्लिकेशनचे प्रोफाइल करा आणि जिथे त्यांची सर्वात जास्त गरज आहे तिथे धोरणात्मकपणे ऑप्टिमायझेशन लागू करा.
useCallback च्या मागचे "का" समजून घेऊन आणि या सर्वोत्तम पद्धतींचे पालन करून, तुम्ही अंदाजे काम करण्यापलीकडे जाऊन तुमच्या React ॲप्लिकेशन्समध्ये (applications) माहितीपूर्ण, प्रभावी कार्यक्षमतेत सुधारणा करण्यास सुरुवात करू शकता, असे वापरकर्ता अनुभव निर्माण करू शकता जे केवळ वैशिष्ट्यपूर्णच नाहीत तर प्रवाही आणि प्रतिसाद देणारे (fluid and responsive) देखील आहेत.