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);
// مستحکم ریفرنس — deps تبدیل ہونے تک وہی فنکشن
const handleClick = useCallback(() => {
setCount(prev => prev + 1);
}, []);
return <Child onClick={handleClick} />;
}
useCallback میں میموائزیشن فنکشن کال کے نتیجے کو کیش کرنے پر مبنی ہے۔ React پہلے رینڈر کے وقت بنائے گئے بندش (closure) کو محفوظ رکھتا ہے اور بعد کے رینڈرز میں اسے لوٹاتا ہے جب تک انحصار تبدیل نہ ہوں۔ فائبر نوڈ کے اندر، ہر 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 میں لپٹا ہے اور ایک prop کے طور پر کال بیک فنکشن وصول کرتا ہے، تو 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 میں پرانے بندش (stale closure) کا مسئلہ استعمال شدہ تمام متغیرات کو انحصار کی صف میں شامل کرکے حل کیا جاتا ہے۔ 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 استعمال کریں — ایک لائبریری جو دوبارہ رینڈر کی وجہ لاگ کرتی ہے۔ بنیادی وجوہات: prop تبدیل ہوا (کال بیک ریفرنس سمیت)، حالت تبدیل ہوئی، یا سیاق و سباق تبدیل ہوا۔ اگر useCallback مدد نہیں کرتا — چیک کریں کہ تمام انحصار درست طریقے سے مخصوص ہیں۔
React.memo کے بغیر بھی، useCallback سیاق و سباق کی اقدار کے لیے useMemo کے ساتھ مفید ہو سکتا ہے۔ اگر آپ Context.Provider میں فنکشنز کے ساتھ ایک شے پاس کر رہے ہیں، تو شے کی تخلیق کو useMemo میں اور ہر فنکشن کو useCallback میں لپیٹیں۔ یہ کسی ایک فنکشن کے تبدیل ہونے پر تمام سیاق و سباق استعمال کرنے والوں کے دوبارہ رینڈر کو روکتا ہے۔ لیکن React.memo کے بغیر براہ راست props میں کال بیک پاس کرنے پر useCallback کا کوئی فائدہ نہیں ہے۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں