تعلّم متى تُسرّع React.memo و useMemo و useCallback تطبيقك فعلاً، ومتى تُعقّده بلا طائل.
افتح هذا الدرس في Kodokonعندما يُعاد تصيير مكوّن، يُعاد تصيير كل أبنائه افتراضيًا، سواء تغيرت props الخاصة بهم أم لا. وهذه ليست مأساة: لا يمسّ التصيير الـ DOM إلا إذا تغيّر الناتج. تصبح المذاكرة ذات صلة عندما تلتقي عمليات التصيير المتكررة بشجرات فرعية باهظة التكلفة. ثلاث أدوات، ثلاثة أهداف: React.memo يتخطى تصيير مكوّن إذا كانت props الخاصة به متساوية سطحيًا، و useMemo يُخزّن قيمة محسوبة، و useCallback يُخزّن دالة. تعتمد الثلاث جميعًا على تساوي المراجع.
import { memo } from "react";
const Row = memo(function Row({ item, onSelect }) {
return (
<li onClick={() => onSelect(item.id)}>{item.label}</li>
);
});قوة السلسلة من قوة أضعف حلقاتها. إذا تلقّت prop واحدة مرجعًا جديدًا في كل تصيير - دالة سهم مضمّنة، أو كائن أو مصفوفة حرفية - فشلت مقارنة memo وأُعيد تصيير المكوّن على أي حال. يُثبّت useCallback مرجع الدالة كي تنجح المقارنة.
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>
);
}لـ useMemo استخدامان مشروعان: تفادي حساب باهظ فعلاً (فرز أو تجميع آلاف العناصر)، وتثبيت مرجع يستهلكه ابن مُذاكَر أو مُدرَج في تبعيات تأثير. أما بالنسبة لحساب تافه، فالتخزين المؤقّت يكلّف أكثر مما يوفّر: مقارنة التبعيات، وذاكرة محتجزة، وقراءة أثقل.
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>;
}