useCallback — funksiyaning memorizatsiya qilingan versiyasini qaytaradigan React hook-i; bu versiya uning bog'liqliklari o'zgarmaguncha renderlar orasida o'zgarmaydi. Komponent ichida funksiyani odatiy e'lon qilishdan (har renderda yangi funksiya yaratadigan) farqli o'laroq, useCallback funksiyaga havolani barqarorlashtiradi, bu esa React.memo orqali optimallashtirilgan child komponentlarning keraksiz re-renderlarining oldini oladi. React Documentation (2025) ma'lumotlariga ko'ra, useCallback faqat React.memo bilan yoki barqaror havolaga bog'liq bo'lgan hook'lar bilan birgalikda foydalidir.
Asosiy narsalar
useCallback — React 16.8 ga qo'shilgan, funksiyani memorizatsiya qiluvchi hook: bog'liqliklar o'zgarmaguncha xuddi shu havolani qaytaradi. useCallback'siz komponent ichida funksiyaning har bir e'loni har renderda yangi funksiya obyektini yaratadi. Primitivlar uchun bu sezilmaydi, lekin bunday callback'larni React.memo orqali optimallashtirilgan child komponentlarga uzatganda har bir yangi havola child komponentning re-renderiga sabab bo'ladi.
Sintaktik jihatdan useCallback funksiya uchun useMemo'ga teng: useCallback(fn, deps) — bu useMemo(() => fn, deps) uchun qisqartma. React memorizatsiya qilingan funksiyani fiber tugunining ichki xotirasida saqlaydi va har renderda bog'liqliklarni taqqoslaydi. Agar bog'liqliklar o'zgarmagan bo'lsa (har element uchun Object.is), avvalgi funksiya qaytariladi.
React Documentation — useCallback (2025) ma'lumotlariga ko'ra, har bir funksiyani useCallback'ga o'rash shart emas. Hook o'z narxiga ega: hook'ni chaqirish, bog'liqliklarni taqqoslash va bog'liqliklar massivi uchun xotira ajratish. Agar komponent sodda bo'lsa va React.memo bilan chuqur daraxtlarga ega bo'lmasa — useCallback faqat ilovani sekinlashtiradi. Optimallashtirish intuitiv emas, o'lchanadigan bo'lishi kerak.
import { useCallback } from 'react';
function Parent() {
const [count, setCount] = useState(0);
// Barqaror havola — deps o'zgarmaguncha bir xil funksiya
const handleClick = useCallback(() => {
setCount(prev => prev + 1);
}, []);
return <Child onClick={handleClick} />;
}
useCallback'dagi memorizatsiya funksiyani chaqirish natijasini keshlashga asoslangan. React birinchi render paytida yaratilgan closure'ni saqlab qoladi va bog'liqliklar o'zgarmaguncha keyingi renderlarda uni qaytaradi. Fiber tuguni ichida har bir useCallback chaqiruvi hook'lar bog'langan ro'yxatida tugun yaratadi; u yerda avvalgi bog'liqliklar va memorizatsiya qilingan qiymat saqlanadi.
Bog'liqliklarni taqqoslash jarayoni qat'iy ravishda Object.is orqali amalga oshiriladi — bu obyektlar yoki massivlarni chuqur tekshirmasdan sayoz taqqoslashdir. Agar bog'liqliklarda obyekt yoki massiv bo'lsa, har renderdagi yangi havola o'zgarish deb hisoblanadi. Shuning uchun bog'liqliklar massiviga primitiv qiymatlar yoki barqaror havolalar (masalan, useRef yoki useMemo'dan) uzatish kerak.
React Core Team — Optimization Guide (2024) ma'lumotlariga ko'ra, memorizatsiya narxi uch komponentdan iborat: har renderda bog'liqliklar massivini ajratish, elementlarni Object.is orqali aylanib taqqoslash va qayta yaratishda garbage collector'ning potensial yuki. Yuzlab useCallback o'ramlariga ega komponent uchun bu sezilarli bo'lishi mumkin — shuning uchun hook'ni qo'llashda tanlanganlik muhim ahamiyatga ega.
| Ssenariy | useCallback'siz | useCallback bilan |
|---|---|---|
| Funksiya yaratish | Har renderda yangi | Barqaror deps bilan bir xil |
| React.memo'ga uzatish | Child re-render bo'ladi | Child re-render bo'lmaydi |
| useEffect massivida | Effekt qayta ishga tushadi | Effekt barqaror |
| Yuklama | Minimal | Bog'liqliklarni taqqoslash + xotira |
Keng tarqalgan afsona shundaki, useCallback ishlashni avtomatik yaxshilaydi. Aslida, yakkalangan holda (React.memo'siz) useCallback bog'liqliklarni taqqoslash narxi tufayli ilovani biroz sekinlashtiradi. Hook faqat uchta ssenariyda haqiqiy foyda keltiradi: React.memo komponentlarining re-renderini oldini olish, useEffect'dagi callback'larning barqarorligi va reference equality'ga bog'liq bo'lgan custom hook'larga uzatish.
Qoida sodda: React DevTools Profiler orqali ishlash muammosini aniqlamaguningizcha — useCallback'dan foydalanmang. React jamoasi qayta-qayta ta'kidlagan: vaqtidan oldin optimallashtirish yomonlikning ildizidir. Avval memorizatsiyasiz toza kod yozing, o'lchang, profilerda tor joyni toping va shundan keyingina useCallback'ni haqiqatan kerak bo'lgan joyga qo'shing.
// O'lchanadigan optimallashtirish: Child React.memo'ga o'ralgan
const Child = React.memo(({ onClick }) => {
console.log('Child re-render bo'ldi');
return <button onClick={onClick}>Click</button>;
});
function Parent() {
const handleClick = useCallback(() => {
console.log('bosildi');
}, []);
return <Child onClick={handleClick} />;
}
Dan Abramov — Before You memo() (2024) ma'lumotlariga ko'ra, open-source loyihalarda useCallback qo'llanishining 90 foizdan ortig'i ortiqcha. Dasturchilar har bir funksiyani ehtiyot uchun o'rab, effektni o'lchamaydilar. Muqobil: agar child komponent og'ir bo'lsa va uning re-renderi qimmat bo'lsa — React.memo + useCallback asosli. Agar child komponent yengil bo'lsa — re-render bog'liqliklarni taqqoslashdan arzon.
Birinchi ssenariy — React.memo. Agar child komponent React.memo'ga o'ralgan bo'lsa va prop sifatida callback funksiyasini qabul qilsa, useCallback'siz child komponent o'z ma'lumotlari o'zgarmagan bo'lsa ham, ota-onaning har renderida qayta chiziladi. useCallback havolani barqarorlashtiradi va React.memo re-renderni to'g'ri o'tkazib yubora oladi.
Ikkinchi ssenariy — bog'liqliklarda callback bo'lgan useEffect. Agar funksiya useEffect bog'liqliklari massiviga uzatilsa, har bir yangi havola effektni qayta ishga tushiradi. useCallback havolaning barqarorligini kafolatlaydi va effekt faqat real ma'lumotlar o'zgarganda ishlaydi, har renderda emas. Bu ayniqsa subscription va so'rovlar uchun muhim.
// useCallback barqaror useEffect bog'liqligi uchun
const fetchData = useCallback(async (id) => {
const res = await fetch(`/api/${id}`);
setData(res.data);
}, []); // barqaror havola, hech qachon qayta yaratilmaydi
useEffect(() => {
fetchData(props.id);
}, [props.id, fetchData]); // effekt faqat props.id o'zgarganda ishlaydi
useCallback va useMemo o'rtasidagi asosiy farq — har biri nimani memorizatsiya qilishida. useCallback funksiyani memorizatsiya qiladi: useCallback(fn, deps) fn ni (xuddi shu yoki avvalgi versiyani) qaytaradi. useMemo funksiyani chaqirish natijasini memorizatsiya qiladi: useMemo(() => computeExpensive(a, b), [a, b]) hisoblangan qiymatni qaytaradi, funksiyani emas.
Texnik jihatdan useCallback useMemo ustidagi sintaktik shakar: useCallback(fn, deps) useMemo(() => fn, deps) bilan teng. Bu sintaksis faqat o'qilishi uchun mavjud — dasturchi aniq ko'rishi uchunki, memorizatsiya qilinayotgan narsa qiymat emas, aynan funksiya. useCallback va funksiyali useMemo o'rtasida ishlash farqi yo'q — ular bir xil kodni yaratadi.
| Hook | Memorizatsiya qiladi | Sintaksis | Qo'llanilishi |
|---|---|---|---|
| useCallback | Funksiyani (havolani) | useCallback(fn, deps) | Child komponentlar uchun callback'lar |
| useMemo | Hisoblash natijasini | useMemo(() => value, deps) | Qimmat hisoblashlar, obyektlarni memorizatsiya qilish |
// Bular ekvivalent:
const handleClick = useCallback(() => doSomething(a, b), [a, b]);
const handleClick = useMemo(() => () => doSomething(a, b), [a, b]);
Eng keng tarqalgan xato — barcha funksiyalarni child komponentlarda React.memo'siz useCallback'ga ma'nosiz o'rash. Agar child komponent React.memo'ga o'ralmagan bo'lsa, u callback havolasi o'zgarishidan qat'i nazar, har holda ota-onaning har renderida re-render bo'ladi. React.memo'siz useCallback — foydasiz xarajat.
// ❌ Foydasiz: child'da React.memo yo'q
const handle = useCallback(() => doStuff(), []);
<Child onClick={handle} />; // Child React.memo'siz baribir re-render bo'ladi
// ❌ Stale closure: bog'liqlik yetishmayapti
const handle = useCallback(() => {
console.log(count); // count doim 0 — stale closure!
}, []);
// ✅ To'g'ri: bog'liqliklarni kiriting
const handle = useCallback(() => {
console.log(count);
}, [count]);
useCallback'dagi stale closure muammosi bog'liqliklar massiviga ishlatiladigan barcha o'zgaruvchilarni kiritish bilan hal qilinadi. exhaustive-deps bilan eslint-plugin-react-hooks callback tanasidagi barcha o'zgaruvchilarning massivda borligini avtomatik tekshiradi. Agar callback renderlar orasida o'zgarmaydigan setState'ni ishlatsa, uni deps'da xavfsiz ko'rsatish mumkin — React setState'ning barqarorligini kafolatlaydi.
Tez-tez so'raladigan savollar
Yo'q. useCallback faqat uchta holatda ma'noga ega: child komponent React.memo'ga o'ralgan, funksiya useEffect bog'liqliklari massivida ishlatiladi yoki funksiya reference equality'ga bog'liq custom hook'ga uzatiladi. Boshqa holatlarda useCallback foydasiz yuklama qo'shadi. React jamoasi avval optimallashtirishsiz yozishni va ularni profillash natijalariga ko'ra qo'shishni tavsiya qiladi.
Oddiy komponentlar uchun — har renderda yangi funksiya biroz tezroq, chunki useCallback bog'liqliklarni taqqoslash va massiv ajratishga resurs sarflaydi. React.memo'ning chuqur daraxtlariga ega komponentlar uchun — useCallback g'alaba qozonadi, minglab child elementlarning re-renderini oldini oladi. O'lchang va solishtiring, taxmin qilmang — obyektiv baholash uchun React DevTools Profiler'dan foydalaning.
Ha, useCallback async funksiyalar bilan sinxron funksiyalar kabi ishlaydi. Hook funksiyaning o'zini memorizatsiya qiladi, natija (Promise) esa har chaqiruvda qaytariladi. useCallback ichidagi asinxron funksiya — useEffect'da ishlatiladigan barqaror ma'lumot yuklash callback'larining keng tarqalgan namunasi: const fetchData = useCallback(async (id) => {...}, []).
React DevTools Profiler'dan foydalaning — qaysi komponentlar re-render bo'layotganini va nima uchun ekanini ko'rsatadi. Dasturiy tekshirish uchun console.log yoki useWhyDidYouUpdate — re-render sababini qayd etuvchi kutubxonani qo'shing. Asosiy sabablar: prop o'zgargan (callback havolasi ham), state yoki kontekst o'zgargan. Agar useCallback yordam bermasa — barcha bog'liqliklar to'g'ri ko'rsatilganini tekshiring.
React.memo'siz ham useCallback kontekst value uchun useMemo bilan kombinatsiyada foydali bo'lishi mumkin. Agar Context.Provider'ga funksiyalari bo'lgan obyekt uzatayotgan bo'lsangiz, obyekt yaratishni useMemo'ga, har bir funksiyani esa useCallback'ga o'rang. Bu funksiyalardan biri o'zgarganda kontekstning barcha iste'molchilari re-renderining oldini oladi. Lekin React.memo'siz props'ga callback'larni to'g'ridan-to'g'ri uzatishda useCallback foyda keltirmaydi.
Xulosa
Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz
IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.