Kodokon kodokon.com

Memoization: memo, useMemo, useCallback

सीखें कि React.memo, useMemo और useCallback आपके ऐप को वास्तव में कब तेज़ करते हैं, और कब वे उसे बिना वजह जटिल बना देते हैं।

10 मिनट · 3 प्रश्न

इस पाठ को Kodokon में खोलें

जब कोई कंपोनेंट फिर से render होता है, तो डिफ़ॉल्ट रूप से उसके सभी children फिर से render होते हैं, चाहे उनके props बदले हों या नहीं। यह कोई त्रासदी नहीं है: एक render केवल तभी DOM को छूता है जब आउटपुट बदलता है। Memoization तब प्रासंगिक हो जाता है जब बार-बार होने वाले renders महँगे subtrees से मिलते हैं। तीन उपकरण, तीन लक्ष्य: React.memo किसी कंपोनेंट का render छोड़ देता है यदि उसके props उथले रूप से समान हों, useMemo एक गणना किए गए मान को cache करता है, useCallback एक फ़ंक्शन को cache करता है। तीनों reference समानता पर निर्भर करते हैं।

JSX
import { memo } from "react";

const Row = memo(function Row({ item, onSelect }) {
  return (
    <li onClick={() => onSelect(item.id)}>{item.label}</li>
  );
});
Row केवल तभी फिर से render होता है जब item या onSelect का reference बदलता है।

श्रृंखला उतनी ही मज़बूत होती है जितनी उसकी सबसे कमज़ोर कड़ी। यदि कोई एक भी prop हर render पर एक नया reference प्राप्त करता है - एक inline arrow function, एक object या array literal - तो memo की तुलना विफल हो जाती है और कंपोनेंट फिर भी render हो जाता है। useCallback फ़ंक्शन के reference को स्थिर करता है ताकि तुलना सफल हो।

JSX
import { useCallback } from "react";

function List({ items }) {
  const handleSelect = useCallback((id) => {
    console.log("selected:", id);
  }, []);

  return (
    <ul>
      {items.map((item) => (
        <Row
          key={item.id}
          item={item}
          onSelect={handleSelect}
        />
      ))}
    </ul>
  );
}
handleSelect हर render पर वही reference बनाए रखता है।

useMemo के दो वैध उपयोग हैं: एक सचमुच महँगी गणना से बचना (हज़ारों items को क्रमबद्ध करना या समुच्चयित करना), और एक memoized child द्वारा उपभोग किए जाने वाले या किसी effect की dependencies में सूचीबद्ध reference को स्थिर करना। एक मामूली गणना के लिए, cache जितना बचाता है उससे अधिक खर्च करता है: dependency तुलना, बनाए रखी गई memory, भारी पढ़ना।

JSX
import { useMemo } from "react";

function Stats({ orders }) {
  const total = useMemo(() => {
    return orders.reduce(
      (sum, order) => sum + order.amount,
      0
    );
  }, [orders]);

  return <p>Total: {total} €</p>;
}
total की गणना केवल तभी फिर से होती है जब orders का reference बदलता है।

ज्ञान जांच

सुनिश्चित करें कि आपको इस पाठ के मुख्य बिंदु याद हैं।

  1. एक child React.memo में लपेटा गया है, लेकिन उसका parent उसे एक inline arrow function prop के रूप में पास करता है। परिणाम?
    • Memoization काम करता है: functions की तुलना उनके source code से होती है
    • Memoization अप्रभावी है: inline function हर render पर एक नया reference बनाता है और तुलना विफल हो जाती है
    • React development में एक चेतावनी उठाता है
  2. जब तक a नहीं बदलता, useCallback(fn, [a]) क्या गारंटी देता है?
    • कि function कभी memory में फिर से नहीं बनता
    • कि function केवल एक बार चलाया जाएगा
    • कि एक render से दूसरे तक वही function reference लौटाया जाता है
  3. किस मामले में useMemo स्पष्ट रूप से उचित है?
    • एक महँगी गणना, या एक memoized child या किसी effect dependency के लिए स्थिर करने योग्य reference
    • कोई भी व्युत्पन्न मान, एहतियात के तौर पर
    • कंपोनेंट के दो mounts के बीच डेटा को cache करना