في هذا الدرس 6تصفّح المواضيع
في كثير من لوحات التحكم تشترك حالة عُليا في نفس المكون الأب الذي يعرض جدولاً ضخماً أو مخططاً بيانياً معقداً، بحيث يتعذر فصل الحالة بالأسفل. هنا يأتي دور الدالة العليا memo() المستوردة من react والمعروفة أيضاً باسم React.memo().
عند تغليف مكون دالي نقي بالصيغة memo(function RevenueCard(props) { ... })، فإنك تخبر React بوضوح: «إذا أُعيد تصيير الأب وبقيت جميع خصائصي مطابقة للتصيير السابق، فتخطَّ تشغيل دالتي وأعد استخدام النتيجة السابقة فوراً».
import { memo, useState } from 'react';
const RevenueCard = memo(function RevenueCard(props) {
return (
<article>
<h3>{props.quarter}: {props.total} USD</h3>
</article>
);
});
كيف تقرر memo() ما إذا كانت الخصائص قد تغيرت؟ تعتمد على المقارنة السطحية (Shallow Equality)، حيث تمر على كل مفتاح في كائن الخصائص السابق والجديد وتقارن قيمتهما بالدالة المعيارية Object.is(prevProp, nextProp).
بالنسبة للقيم الأولية كالأرقام والنصوص والقيم المنطقية تقارن الدالة القيمة ذاتها، أما الكائنات والمصفوفات والدوال فتفحص ما إذا كان المتغيران يشيران إلى نفس العنوان المرجعي في الذاكرة أم لا.
بسبب الاعتماد على مقارنة المراجع، فإن تمرير كائن مضمن مباشرة داخل JSX مثل options={{ showGrid: true }} يُبطل مفعول memo() بصمت! ففي كل مرة يعمل فيها الأب تنشئ اللغة كائناً جديداً في الذاكرة فتكون نتيجة المقارنة false دائماً.
قبل اللجوء لأي خطافات إضافية، طبّق حلين بسيطين وفعالين: ارفع كائنات الإعدادات الثابتة خارج دالة المكون كثابت على مستوى الملف، أو مرر القيم المفردة كخصائص أولية مباشرة مثل showGrid={true}، وسنتعلم في الدرس 44 تثبيت الكائنات والدوال الديناميكية.
const CHART_THEME = { stroke: '#7750b2' };
const MetricChart = memo(function MetricChart(props) {
return (
<p>{props.theme.stroke} | {String(props.dense)}</p>
);
});
// <MetricChart theme={CHART_THEME} dense={isDense} />
تقبل دالة memo(Component, arePropsEqual) معاملاً ثانياً اختيارياً هو دالة مقارنة مخصصة تعيد true عند اعتبار الخصائص متكافئة. عملياً في هندسة React الحديثة، يُنصح بتجنب المقارنات المخصصة إلا في حالات نادرة جداً.
فإذا قارنت الدالة المخصصة المعرّف النصي ونسيت مقارنة دالة حدث أو خاصية حالة أخرى، سيتجمد المكون على بيانات قديمة خاطئة! كما أن المقارنة العميقة لكائنات ضخمة في كل تصيير قد تستغرق وقتاً أطول من رسم المكون نفسه.
متى يحقق تغليف React.memo مكسباً ملموساً يستحق الإضافة؟ يبرع هذا الأسلوب مع المكونات العرضية النقية متوسطة أو ثقيلة الوزن—كالجداول الكبيرة والمخططات ومعاينات النصوص الطويلة—عندما يتكرر تصيير المكون الأب باستمرار بينما تبقى خصائص هذا الابن ثابتة في أغلب التحديثات:
const Leaderboard = memo(function Leaderboard(props) {
const rows = TRACKS.filter(
(t) => t.score >= props.minScore
);
return <p>Qualified tracks: {rows.length}</p>;
});
// Unrelated parent pulses skip Leaderboard!
تجنب تغليف كل زر صغير أو شارة نصية بدالة memo() بدافع العادة. فإذا كان المكون خفيفاً جداً أو كانت خصائصه تتغير فعلياً في كل تصيير كعداد الثواني الحي، فإن memo() ستجري حلقة فحص للخصائص ثم تعيد رسم المكون على أي حال، فتتحول إلى عبء إضافي بلا فائدة. يلخص الجدول التالي قرارات الاستخدام السليمة:
| حالة المكون الفرعي | أثر تغليف React.memo | القرار الهندسي الموصى به |
|---|---|---|
| مخطط أو جدول ثقيل بخصائص أولية ثابتة | يتخطى إعادة التصيير المكلفة بكفاءة عالية | غلّفه بـ memo وتأكد من النتيجة عبر Profiler |
| زر بسيط أو شارة نصية خفيفة جداً | تكلفة فحص الخصائص تعادل رسم العنصر نفسه | اتركه مكوناً دالياً عادياً لنظافة الكود |
| خصائصه تتغير فعلياً مع كل تصيير للأب | يجري المقارنة ثم يعيد الرسم في كل مرة | لا تغلفه لأن الفحص يصبح عملاً ضائعاً |
| يستقبل كائناً مضمناً جديداً في كل رسم | تفشل المقارنة السطحية ويعاد الرسم دائماً | مرر قيماً أولية أو ثبّت مرجع الكائن أولاً |
ملخص الدرس
حصاد الدرسمراجعة مركّزة لأهم المفاهيم والقواعد الهندسية التي أتقنتها في هذا الدرس قبل التطبيق العملي
ماذا تعلّمت في هذا الدرس؟
تعلمت في هذا الدرس كيف يتخطى تغليف React.memo إعادة التصيير الفائضة بالمقارنة السطحية عبر Object.is، ولماذا تكسر الكائنات المضمنة ثبات المرجع، ومتى يحقق التغليف فائدة حقيقية أو يصبح عبئاً غير مبرر. الخطوة التالية: انتقل الآن إلى الدرس رقم 44 «تخزين الحسابات والدوال عبر useMemo وuseCallback» لمواصلة البناء التراكمي المتدرج في مسار React الحديث.
سجّل الدخول لحفظ تقدمك
تابع إنجاز المواضيع والمصطلحات والمهام، وكمّل من آخر خطوة على أي جهاز.
المصطلحات4
راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.
- 01 React.memo الدالة العليا memo
- غلاف دالي في React يتخطى إعادة تصيير المكون النقي إذا لم تتغير أي من خصائصه الممررة من الأب.
- للمراجعة
- 02 Shallow Equality المقارنة السطحية
- فحص كل خاصية في المستوى الأول بين الكائن السابق والجديد عبر Object.is دون الغوص في الحقول المتداخلة.
- للمراجعة
- 03 Reference Equality تطابق المرجع بالذاكرة
- اعتبار كائنين أو مصفوفتين أو دالتين متساويتين فقط عندما يشيران إلى نفس الموقع المرجعي في الذاكرة.
- للمراجعة
- 04 Pure Component المكون الدالي النقي
- مكون دالي يعيد دائماً نفس مخرجات JSX تماماً طالما استقبل نفس الخصائص والحالة والسياق دون آثار جانبية.
- للمراجعة
لا توجد بطاقات تطابق البحث والتصفية.
اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.
الاختصارات4
راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.
- 01 HOC HOC
- Higher-Order Component
- دالة مثل React.memo تستقبل مكوناً برمجياً وتُعيد مكوناً محسناً بسلوك إضافي.
- للمراجعة
- 02 UI UI
- User Interface
- شجرة واجهة المستخدم التي تعيد memo توظيف أجزائها الثابتة دون إعادة حساب.
- للمراجعة
- 03 JS JS
- JavaScript
- لغة التشغيل التي تقارن الأنواع الأولية بالقيمة وتقارن الكائنات والدوال بالمرجع.
- للمراجعة
- 04 NaN NaN
- Not-a-Number
- قيمة عددية خاصة تعاملها الدالة Object.is على أنها مساوية لنفسها بأمان أثناء فحص الخصائص.
- للمراجعة
لا توجد بطاقات تطابق البحث والتصفية.
اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.
مهامك قبل الاختبار
خطوة صغيرة كل مرة. وإنجاز تقدر ترجع له.
-
افتح مثال RevenueCard في محرر التجريب واكتب في حقل الأب وتأكد من بقاء عداد تصيير البطاقة عند 1 حتى تضغط زر تبديل الربع المالي.
-
اضغط زر النبض الحي في الأب عدة مرات وتأكد أن إشعار Profiler للمكون الفرعي لا يعمل إلا عند تغيير الحد الأدنى للدرجة.
تأشير المهمة إقرار منك بإتمامها، وليس تصحيحًا آليًا للكود. يُحفظ تقدمك في حسابك.
اختبر فهمك.
ووصلها للإتقان.
كل سؤال خطوة لقدّام. اختار، اكتب كود، وشوف نتيجتك فورًا.
أكمل المهام، واجمع كل الإجابات الصحيحة. أقل من 100%؟ راجع وأعد المحاولة.
الأسئلة متاحة للاطلاع. سجّل الدخول للتفاعل وحفظ تقدمك.
لمحة عن التحدي10 أسئلة تنتظرك +
ماذا يحقق تغليف المكون الدالي النقي بالدالة React.memo؟
يتيح لمكتبة React تخطي إعادة رسم المكون عند تصيير أبيه طالما لم تتغير خصائصه الممررة.
ما أداة المقارنة القياسية في JavaScript التي تستخدمها React.memo لفحص كل خاصية؟
تفحص React كل خاصية سابقة وجديدة باستخدام الدالة القياسية Object.is.
إذا قام مكون مغلف بـ React.memo بتحديث حالته الداخلية عبر useState فسيُعاد تصييره بشكل طبيعي.
صواب؛ فالتغليف يمنع التصيير غير الضروري القادم من الأب فقط ولا يمنع تحديثات الحالة الداخلية للمكون.
لماذا يؤدي تمرير كائن مضمن مثل style={{ padding: 12 }} داخل الأب إلى إبطال فائدة React.memo على المكون الفرعي؟
لأن كل تصيير للأب ينشئ كائناً جديداً بموقع مختلف في الذاكرة فتعيد Object.is القيمة false.
كيف تمرر كائن إعدادات ثابت لا يتغير لمكون مغلف بـ memo دون كسر المساواة السطحية أو إضافة خطافات؟
بتعريف الكائن الثابت مرة واحدة خارج دالة المكون في المستوى الأعلى للملف.
كتابة دالة مقارنة عميقة مخصصة arePropsEqual تُعد غالباً أسرع وأكثر أماناً من تمرير خصائص أولية واضحة.
خطأ؛ فالمقارنات المخصصة عرضة لنسيان بعض الخصائص وتجميد الواجهة على قيم قديمة فضلاً عن تكلفتها الحسابية.
لماذا يُفضل كتابة دالة مسماة داخل memo بدلاً من دالة سهمية مجهولة؟
لأن الدالة المسماة تظهر باسمها الواضح في أدوات مطوري React ومخطط اللهب مما يسهل الفحص.
متى يصبح تغليف المكون بـ React.memo عملاً ضائعاً بدلاً من تسريع التطبيق؟
عندما يكون المكون خفيفاً جداً أو تتغير خصائصه فعلياً في كل تصيير للأب.
تُرجع الدالة Object.is(NaN, NaN) القيمة true، مما يسمح لـ React.memo باعتبار قيمة NaN الثابتة غير متغيرة.
صواب؛ تعالج دالة Object.is هذه الحالة الحدية بدقة فلا يتكرر التصيير بلا داعٍ.
أي مكون من المكونات التالية يُعد المرشح الأقوى للاستفادة من تغليف React.memo؟
مخطط إحصائي ثقيل داخل لوحة يتكرر تصيير أبيها بسبب حقل كتابة غير مرتبط ببيانات المخطط.