আসলে কী একটি re-render ট্রিগার করে তা বোঝাই React পারফরম্যান্স নিয়ে যুক্তি করার ভিত্তি — এর বেশিরভাগই স্পষ্টভাবে বলার মতো একটি তথ্যে নেমে আসে।
একটি কম্পোনেন্টের state বদলালে (একটি useState setter-এর মাধ্যমে), React সেই কম্পোনেন্ট আর এর প্রতিটি child কম্পোনেন্ট re-render করে — সেই child-দের নিজস্ব props আসলে বদলেছে কিনা তা নির্বিশেষে। এটা ইচ্ছাকৃত, আর ডিফল্টভাবে সঠিক: বেশিরভাগ বাস্তব কম্পোনেন্টে এটা সস্তা।
function Parent() {
const [count, setCount] = useState(0);
return (
<div>
<button onClick={() => setCount(count + 1)}>{count}</button>
<ExpensiveChild /> {/* re-renders every time count changes, even with no props of its own */}
</div>
);
}এমন একটি কম্পোনেন্টের জন্য যা re-render করা সত্যিকারভাবে ব্যয়বহুল আর বেশিরভাগ সময় একই props পায়, React.memo এর props না বদলালে এটা re-render করা এড়িয়ে যায়:
const ExpensiveChild = React.memo(function ExpensiveChild({ data }) {
// only re-renders when `data` actually changes
return <ComplexVisualization data={data} />;
});React.memo সাহায্য করতে স্থিতিশীল প্রপ রেফারেন্স দরকার
React.memo === দিয়ে props তুলনা করে — Updating State পাঠের একই রেফারেন্স চেক। প্রতিটি parent render-এ নতুনভাবে তৈরি একটি নতুন অবজেক্ট বা অ্যারে লিটারেল (<ExpensiveChild data={{ x: 1 }} />) এটাকে সম্পূর্ণভাবে অকার্যকর করে দেয়, কারণ ভেতরের মান একই রকম দেখতে হলেও এটা আসলে কখনো আগের render-এর অবজেক্টের সমান হয় না। এখানেই আগের পাঠের useMemo নিজের জায়গা করে নেয় — শুধু child-এর render নয়, অবজেক্টটাকেই memoize করে।
React DevTools-এর Profiler ট্যাব ঠিক দেখায় কোন কম্পোনেন্ট re-render হয়েছে আর প্রতিটিতে কত সময় লেগেছে — কিছু ধীর মনে হলে কোন কম্পোনেন্টকে React.memo-এ মোড়াবেন তা অনুমান করার বদলে এটাই সঠিক প্রথম ধাপ।
বেশিরভাগ কম্পোনেন্টের একদমই React.memo, useMemo, বা useCallback-এর দরকার হয় না — আগে সাধারণ কম্পোনেন্ট লিখুন, আর Profiler একটি আসল, মাপা সমস্যা দেখানোর পরেই নির্দিষ্টভাবে এদের দিকে যান। এটা useMemo/useCallback পাঠের একই সতর্কতার প্রতিফলন: ডিফল্টভাবে ব্যবহৃত অপ্টিমাইজেশন টুল এমন একটি সুবিধার জন্য আসল জটিলতা যোগ করে যা বেশিরভাগ সময় আসলে নেই।