المتجر · فصل ٤

السليكتور وإعادة الرسم

useShallow · shallow · equality
🎯 الهدف: تقرا أكتر من حقل من غير لوب، وتعرف امتى المقارنة السطحية.

السليكتور اللي يرجّع قيمة ثابتة المقارنة بـ Object.is: رقم، نص، أو نفس الدالة. المكوّن يعيد الرسم لما القيمة دي تتغير.

من الإصدار الخامس، كائن جديد في كل نداء يعتبر قيمة مختلفة حتى لو الحقول زي بعض. السطر ده يعمل لوب تحديث:

loop.jsx
const { items, add } = useCart((state) => ({  items: state.items,  add: state.add,}));

الحل الأنضف: سليكتور لكل حقل. مفيش غلاف جديد.

split.jsx
const items = useCart((state) => state.items);const add = useCart((state) => state.add);

useShallow

لو محتاج كذا حقل في نداء واحد، لف السليكتور بـ useShallow. المقارنة تبقى على الحقول، مش على الغلاف.

shallow-pick.jsx
import { useShallow } from "zustand/react/shallow";const { items, note } = useCart(  useShallow((state) => ({ items: state.items, note: state.note })),);

نفس الفكرة لمصفوفة مفاتيح بتتبني كل مرة: طالما العناصر بالمقارنة السطحية زي القديم، مفيش رسم زيادة.

shallow دالة المقارنة نفسها، لو حابب تمرّرها بإيدك. useShallow بيركّبها على السليكتور.

مساواة على الهوك كله

createWithEqualityFn زي create، بس كل سليكتور يتقارن بالدالة اللي تديها. useStoreWithEqualityFn نفس الفكرة على متجر vanilla. الاتنين من مدخل zustand/traditional. راجع المسار في الدوكس.

ده أنسب لو أغلب القراءات بترجع كائنات. لالتقاط حقول قليلة، useShallow أحدّ.

سليكتورات تتولد

المكتبة مش بتصدّر مولّد. الوصفة تمشي على مفاتيح getState وتعمل لكل مفتاح دالة use.field بتنادي السليكتور. في حزم خارجية بتعمل كده، زي auto-zustand-selectors-hook. الوصفة دي مش بتستبدل useShallow لو بترجع كائن مركّب.

خلّصت الفصل لما

🧠 اختبر نفسك
١) ليه الكائن جوه السليكتور عمل Maximum update depth؟
الغلاف جديد كل مرة، و Object.is يفشل، فالاشتراك يتجدد في لوب.
٢) useShallow بيقارن إيه؟
حقول الناتج مستوى واحد، مش مرجع الغلاف.
٣) مولّد السليكتورات دالة من المكتبة؟
لأ. وصفة أو حزمة خارجية. كل مفتاح ياخد هوك صغير.