React.memo: nə zaman kömək edir, nə zaman zərər verir
-
React tətbiqlərində performans optimizasiyası üçün tez-tez istifadə olunan
React.memo
komponenti, düzgün istifadə edildikdə faydalı ola bilər. Lakin, bəzi hallarda bu alət gözlənilməz nəticələrə səbəb ola bilər. Bu məqalədəReact.memo
-nun necə işlədiyini, hansı hallarda effektiv olduğunu və hansı hallarda problem yaratdığını araşdıracağıq.
Memoizasiyanın vəd etdikləri
React tətbiqləri yavaşladıqda, proqramçılar tez-tez
React.memo
,useMemo
vəuseCallback
kimi memoizasiya alətlərinə müraciət edirlər. Bu alətlər, lazımsız yenidən renderlərin qarşısını almaqla performansı artırmaq məqsədi daşıyır. Lakin, bu alətlərin istifadəsi düşündüyümüzdən daha mürəkkəb ola bilər.
JavaScript-də referans müqayisələri
JavaScript-də primitiv dəyərlər (məsələn, ədədlər, sətirlər) dəyərə görə müqayisə olunur, obyektlər isə referansa görə:
// Primitiv dəyərlər dəyərə görə müqayisə olunur const a = 1; const b = 1; console.log(a === b); // true // Obyektlər referansa görə müqayisə olunur const objA = { id: 1 }; const objB = { id: 1 }; console.log(objA === objB); // false, fərqli referanslar
Bu, React-də problem yarada bilər, çünki komponentlərə ötürülən obyekt və funksiyalar hər renderdə yeni referanslara sahib olur və bu, lazımsız yenidən renderlərə səbəb ola bilər.
useMemo
vəuseCallback
necə işləyirReact, referansların sabit qalmasını təmin etmək üçün
useMemo
vəuseCallback
hook-larını təqdim edir.- useMemo: Məhsuldar (expensive) hesablamaların nəticəsini yadda saxlayır və yalnız asılılıqlar dəyişdikdə yenidən hesablayır.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
- useCallback: Funksiyaların referansını yadda saxlayır və yalnız asılılıqlar dəyişdikdə yeni funksiyanı yaradır.
const memoizedCallback = useCallback(() => { doSomething(a, b); }, [a, b]);
React.memo necə işləyir
React.memo
yüksək səviyyəli bir komponentdir (HOC) və komponentin props-larını səthi (shallow) şəkildə müqayisə edərək, dəyişiklik olmadıqda yenidən renderin qarşısını alır:const MyComponent = React.memo(function MyComponent(props) { // komponentin implementasiyası });
Lakin, əgər komponentə ötürülən props-lar hər renderdə yeni referanslara sahib olursa (məsələn, obyektlər və ya funksiyalar),
React.memo
bu dəyişiklikləri görəcək və komponenti yenidən render edəcək.
React.memo istifadəsində ümumi problemlər
1. Props-ların spreading-i
Props-ları yaymaq (spread)
React.memo
-nun effektivliyini poza bilər:const Child = React.memo(({ data }) => { // komponentin implementasiyası }); const Parent = (props) => { return <Child {...props} />; };
Bu halda,
Child
komponentinə ötürülən props-ların referansları dəyişə bilər və bu, yenidən renderə səbəb olar.2. children prop-u problemi
JSX-də
children
də bir prop-dur və hər renderdə yeni referansa sahib olur:const MemoComponent = React.memo(({ children }) => { // implementasiya }); const Parent = () => { return ( <MemoComponent> <div>Some content</div> </MemoComponent> ); };
Bu halda,
MemoComponent
hər dəfə yenidən render olunacaq.3. İç-içə
memo
komponentləri problemiBir-birinin içində yerləşən memo komponentlər də problem yarada bilər:
const InnerChild = React.memo(() => <div>Inner</div>); const OuterChild = React.memo(({ children }) => <div>{children}</div>); const Parent = () => { return ( <OuterChild> <InnerChild /> </OuterChild> ); };
Bu halda,
OuterChild
hər dəfə yenidən render olunacaq, çünkiInnerChild
hər dəfə yeni bir JSX elementi yaradır.Həll yolu:
useMemo
istifadə edərəkInnerChild
-ı yadda saxlamaq:const Parent = () => { const innerChild = useMemo(() => <InnerChild />, []); return <OuterChild>{innerChild}</OuterChild>; };
Memoizasiyanı nə zaman istifadə etməli
React.memo istifadə edin əgər:
- Komponentiniz saf funksional komponentdirsə və eyni props-larla eyni nəticəni qaytarırsa.
- Komponent tez-tez eyni props-larla render olunursa.
- Render prosesi məhsuldardırsa (expensive).
- Profilinq vasitəsilə performans problemi olduğunu təsdiqləmisinizsə.
useMemo istifadə edin əgər:
- Məhsuldar bir hesablamanı hər renderdə təkrar etmək istəmirsinizsə.
- Memoizə edilmiş komponentə ötürülən obyekt və ya array-ın sabit referansını saxlamaq istəyirsinizsə.
- Hesablamanın həqiqətən məhsuldar olduğunu ölçüb təsdiqləmisinizsə.
useCallback istifadə edin əgər:
- Optimallaşdırılmış child komponentlərinə referans bərabərliyinə əsaslanan callback-lar ötürürsünüzsə.
- Callback
useEffect
hook-unda asılılıq kimi istifadə olunursa. - Memoizə edilmiş komponentlərdə sabit funksional referans saxlamaq istəyirsinizsə.
Alternativ: Komponent kompozisiyası
Memoizasiyadan əvvəl, komponent strukturunuzu kompozisiya vasitəsilə yaxşılaşdırmağı düşünün. Komponent kompozisiyası tez-tez performans problemlərini daha zərif şəkildə həll edir.
Məsələn, məhsuldar bir komponenti memoizə etmək əvəzinə, vəziyyəti daha spesifik bir konteynerə keçirin.
Bilik paylaşdıqca artan bir sərvətdir