useCallback — React hook-u, funksiyanın memorizasiya edilmiş versiyasını qaytarır; bu versiya dependency'lər dəyişməyənə qədər renderlər arasında dəyişmir. Komponent daxilində funksiyanın adi elanından (hər renderdə yeni funksiya yaradan) fərqli olaraq, useCallback funksiyaya istinadı stabilləşdirir və bu, React.memo vasitəsilə optimallaşdırılmış uşaq komponentlərin lazımsız re-renderinin qarşısını alır. React Documentation (2025) məlumatına görə, useCallback yalnız React.memo ilə birlikdə və ya sabit istinaddan asılı olan hook'larla işlədikdə faydalıdır.
Əsas məqamlar
useCallback — React 16.8-ə əlavə edilmiş, funksiyanı memorizasiya edən hook-dur: dependency'lər dəyişməyənə qədər eyni istinadı qaytarır. useCallback olmadan komponent daxilində funksiyanın hər elanı hər renderdə yeni funksiya obyekti yaradır. Primitivlər üçün bu nəzərə çarpmır, lakin belə callback'ləri React.memo ilə optimallaşdırılmış uşaq komponentlərə ötürərkən hər yeni istinad uşaq komponentin re-renderinə səbəb olur.
Sintaktik olaraq useCallback funksiya üçün useMemo-ya ekvivalentdir: useCallback(fn, deps) — bu, useMemo(() => fn, deps) üçün qısaltmadır. React memorizasiya edilmiş funksiyanı fiber-qovşağın daxili yaddaşında saxlayır və hər renderdə dependency'ləri müqayisə edir. Dependency'lər dəyişməyibsə (hər element üçün Object.is), əvvəlki funksiya qaytarılır.
React Documentation — useCallback (2025) məlumatına görə, hər funksiyanı useCallback-ə bükmək lazım deyil. Hook-un öz qiyməti var: hook-un çağırılması, dependency'lərin müqayisəsi və dependency massivi üçün yaddaşın ayrılması. Komponent sadədirsə və React.memo ilə dərin ağacları yoxdursa — useCallback yalnız tətbiqi yavaşladacaq. Optimallaşdırma intuitiv deyil, ölçülə bilən olmalıdır.
import { useCallback } from 'react';
function Parent() {
const [count, setCount] = useState(0);
// Sabit istinad — deps dəyişənə qədər eyni funksiya
const handleClick = useCallback(() => {
setCount(prev => prev + 1);
}, []);
return <Child onClick={handleClick} />;
}
useCallback-də memorizasiya funksiya çağırışının nəticəsinin keşləşdirilməsinə əsaslanır. React ilk render anında yaradılmış closure-u saxlayır və dependency'lər dəyişməz qaldıqca sonrakı renderlərdə onu qaytarır. Fiber-qovşağın daxilində hər useCallback çağırışı hook-ların bağlı siyahısında qovşaq yaradır; orada əvvəlki dependency'lər və memorizasiya edilmiş qiymət saxlanılır.
Dependency'lərin müqayisəsi prosesi ciddi şəkildə Object.is vasitəsilə aparılır — bu, obyektlərin və massivlərin dərindən yoxlanılması olmadan dayaz müqayisədir. Dependency'lərdə obyekt və ya massiv varsa, hər renderdəki yeni istinad dəyişiklik kimi qəbul ediləcək. Buna görə dependency massivində primitiv qiymətlər və ya sabit istinadlar (məsələn, useRef və ya useMemo-dan) ötürülməlidir.
React Core Team — Optimization Guide (2024) məlumatına görə, memorizasiyanın dəyəri üç komponentdən ibarətdir: hər renderdə dependency massivinin ayrılması, elementlərin Object.is vasitəsilə gəzilməsi və müqayisəsi və yenidən yaradılma zamanı garbage collector-un potensial yükü. Yüzlərlə useCallback bükməsi olan komponent üçün bu nəzərə çarpan ola bilər — buna görə hook-un istifadəsində seçicilik kritik əhəmiyyət daşıyır.
| Ssenari | useCallback olmadan | useCallback ilə |
|---|---|---|
| Funksiyanın yaradılması | Hər renderdə yeni | Sabit deps ilə eyni |
| React.memo-ya ötürülmə | Uşaq re-render olunur | Uşaq re-render olunmur |
| useEffect massivində | Effekt yenidən işə düşür | Effekt sabitdir |
| Yük | Minimal | Dependency müqayisəsi + yaddaş |
Geniş yayılmış mif odur ki, useCallback avtomatik olaraq performansı yaxşılaşdırır. Əslində, təcrid halda (React.memo olmadan) useCallback dependency'lərin müqayisəsinin dəyərinə görə tətbiqi bir qədər də yavaşladır. Hook yalnız üç ssenaridə real fayda verir: React.memo komponentlərinin re-renderinin qarşısını almaq, useEffect-də callback'lərin sabitliyi və reference equality-dən asılı olan custom hook-lara ötürmə.
Qayda sadədir: React DevTools Profiler vasitəsilə performans problemi aşkar etməyincə — useCallback istifadə etmə. React komandası dəfələrlə vurğulayıb ki, vaxtından əvvəl optimallaşdırma pisliyin köküdür. Əvvəlcə memorizasiyasız təmiz kod yaz, ölç, profiler-də darboğazı tap və yalnız bundan sonra useCallback-i həqiqətən lazım olan yerdə əlavə et.
// Ölçülə bilən optimallaşdırma: Child React.memo-ya bükülüb
const Child = React.memo(({ onClick }) => {
console.log('Child re-render olundu');
return <button onClick={onClick}>Click</button>;
});
function Parent() {
const handleClick = useCallback(() => {
console.log('basıldı');
}, []);
return <Child onClick={handleClick} />;
}
Dan Abramov — Before You memo() (2024) məlumatına görə, open-source layihələrdə useCallback istifadəsinin 90%-dən çoxu artıqdır. Tərtibatçılar hər funksiyanı "ehtiyat üçün" bükür, effekti ölçmürlər. Alternativ: əgər uşaq komponent ağırdırsa və onun re-renderi bahalıdırsa — React.memo + useCallback əsaslıdır. Uşaq komponent yüngüldürsə — re-render dependency'lərin müqayisəsindən ucuzdur.
Birinci ssenari — React.memo. Uşaq komponent React.memo-ya bükülübsə və prop kimi callback funksiyası qəbul edirsə, useCallback olmadan uşaq komponent öz məlumatları dəyişməsə belə, valideynin hər renderində yenidən çəkiləcək. useCallback istinadı stabilləşdirir və React.memo re-renderi düzgün atlaya bilir.
İkinci ssenari — dependency'lərdə callback olan useEffect. Funksiya useEffect-in dependency massivinə ötürülürsə, hər yeni istinad effekti yenidən işə salacaq. useCallback istinadın sabit olmasını təmin edir və effekt yalnız real məlumatlar dəyişdikdə işləyir, hər renderdə deyil. Bu, xüsusilə subscription və sorğular üçün vacibdir.
// useCallback sabit useEffect dependency üçün
const fetchData = useCallback(async (id) => {
const res = await fetch(`/api/${id}`);
setData(res.data);
}, []); // sabit istinad, heç vaxt yenidən yaradılmır
useEffect(() => {
fetchData(props.id);
}, [props.id, fetchData]); // effekt yalnız props.id dəyişdikdə işə düşür
useCallback və useMemo arasındakı əsas fərq ondan ibarətdir ki, hər biri nəyi memorizasiya edir. useCallback funksiyanı memorizasiya edir: useCallback(fn, deps) fn-i (eyni və ya əvvəlki versiyanı) qaytarır. useMemo funksiya çağırışının nəticəsini memorizasiya edir: useMemo(() => computeExpensive(a, b), [a, b]) hesablanmış qiyməti qaytarır, funksiyanı yox.
Texniki olaraq useCallback useMemo üzərində sintaktik şəkərdir: useCallback(fn, deps) useMemo(() => fn, deps) ilə ekvivalentdir. Bu sintaksis yalnız oxunaqlılıq üçün mövcuddur — tərtibatçının aydın görməsi üçün ki, memorizasiya edilən dəyər yox, məhz funksiyadır. useCallback və funksiya ilə useMemo arasında performans fərqi yoxdur — onlar eyni kodu yaradırlar.
| Hook | Memorizasiya edir | Sintaksis | İstifadə |
|---|---|---|---|
| useCallback | Funksiyanı (istinadı) | useCallback(fn, deps) | Uşaq komponentlər üçün callback-lər |
| useMemo | Hesablamanın nəticəsini | useMemo(() => value, deps) | Bahalı hesablamalar, obyektlərin memorizasiyası |
// Bunlar ekvivalentdir:
const handleClick = useCallback(() => doSomething(a, b), [a, b]);
const handleClick = useMemo(() => () => doSomething(a, b), [a, b]);
Ən geniş yayılmış səhv — bütün funksiyaları uşaq komponentlərdə React.memo olmadan useCallback-ə mənasız şəkildə bükməkdir. Uşaq komponent React.memo-ya bükülməyibsə, callback-ə istinadın dəyişməsindən asılı olmayaraq, yenə də valideynin hər renderində re-render olunacaq. React.memo olmadan useCallback — faydasız xərcdir.
// ❌ Faydasız: child-da React.memo yoxdur
const handle = useCallback(() => doStuff(), []);
<Child onClick={handle} />; // Child React.memo olmadan yenə də re-render olunur
// ❌ Stale closure: dependency çatışmır
const handle = useCallback(() => {
console.log(count); // count həmişə 0-dır — stale closure!
}, []);
// ✅ Düzgün: dependency'ləri daxil et
const handle = useCallback(() => {
console.log(count);
}, [count]);
useCallback-də stale closure problemi dependency massivində istifadə olunan bütün dəyişənlərin göstərilməsi ilə həll olunur. exhaustive-deps ilə eslint-plugin-react-hooks avtomatik olaraq callback gövdəsindəki bütün dəyişənlərin massivdə olmasını yoxlayır. Callback renderlər arasında dəyişməyən setState işlədirsə, onu təhlükəsiz şəkildə deps-də göstərmək olar — React setState-in sabitliyinə zəmanət verir.
Tez-tez verilən suallar
Xeyr. useCallback yalnız üç halda məna verir: uşaq komponent React.memo-ya bükülüb, funksiya useEffect-in dependency massivində istifadə olunur və ya funksiya reference equality-dən asılı olan custom hook-a ötürülür. Digər hallarda useCallback faydasız əlavə yük gətirir. React komandası əvvəlcə optimallaşdırmasız yazmağı və onları profilləmənin nəticələrinə görə əlavə etməyi tövsiyə edir.
Sadə komponentlər üçün — hər renderdə yeni funksiya bir qədər sürətlidir, çünki useCallback dependency'lərin müqayisəsinə və massivin ayrılmasına resurs sərf edir. React.memo-nun dərin ağacları olan komponentlər üçün — useCallback qalib gəlir, minlərlə uşaq elementin re-renderinin qarşısını alır. Ölç və müqayisə et, təxmin etmə — obyektiv qiymətləndirmə üçün React DevTools Profiler istifadə et.
Bəli, useCallback async funksiyalarla sinxron funksiyalarla eyni şəkildə işləyir. Hook funksiyanın özünü memorizasiya edir, nəticə (Promise) isə hər çağırışda qaytarılır. useCallback daxilindəki asinxron funksiya — useEffect-də istifadə olunan məlumat yükləmə callback'lərinin sabitliyi üçün geniş yayılmış naxışdır: const fetchData = useCallback(async (id) => {...}, []).
React DevTools Profiler istifadə et — hansı komponentlərin re-render olunduğunu və nə üçün olduğunu göstərəcək. Proqram yoxlaması üçün console.log və ya useWhyDidYouUpdate — re-renderin səbəbini qeyd edən kitabxana əlavə et. Əsas səbəblər: prop dəyişib (callback istinadı daxil olmaqla), state və ya kontekst dəyişib. useCallback kömək etmirsə — bütün dependency'lərin düzgün göstərildiyini yoxla.
React.memo olmadan da useCallback kontekst value üçün useMemo ilə kombinasiyada faydalı ola bilər. Context.Provider-ə funksiyaları olan obyekt ötürürsənsə, obyektin yaradılmasını useMemo-ya, hər funksiyanı isə useCallback-ə bük. Bu, funksiyalardan birinin dəyişməsi zamanı kontekstin bütün istehlakçılarının re-renderinin qarşısını alır. Lakin React.memo olmadan proplara callback'lərin birbaşa ötürülməsində useCallback-in faydası yoxdur.
Yekun
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun