في هذا الدرس 6تصفّح المواضيع
يبدأ تحسين الأداء الحقيقي في React بفهم السؤال الجوهري: ما الذي يُطلق إعادة التصيير فعلياً؟ بعد التركيب الأولي، لا تبدأ React عملية إعادة تصيير إلا عند استدعاء دالة تحديث حالة عبر useState() أو useReducer()، أو عند تغير قيمة مزود سياق Context يقرؤه المكون.
وبمجرد بدء إعادة تصيير المكون الأب، تستدعي React دالته لحساب لقطة JSX الجديدة ثم تعيد افتراضياً تصيير جميع المكونات الأبناء الواقعة داخله لضمان اتساق الواجهة.
function Dashboard() {
const [count, setCount] = useState(0);
return (
<section>
<button onClick={() => setCount(c => c + 1)}>
Refresh Pulse ({count})
</button>
<StaticSummaryBanner />
</section>
);
}
من أكثر المفاهيم المغلوطة شيوعاً بين المبتدئين الاعتقاد بأن «المكون الفرعي لا يعاد تصييره إلا إذا تغيرت خصائصه props». هذا الاعتقاد غير صحيح في السلوك الافتراضي لمكتبة React؛ فعندما يعاد تصيير الأب، تعيد React تشغيل دوال الأبناء مباشرة حتى لو لم يستقبل الابن أي خاصية إطلاقاً.
تُنفَّذ معظم المكونات العادية في أجزاء من المللي ثانية، لذا يظل السلوك الافتراضي سريعاً وآمناً، ولا تظهر المشكلة إلا حين يقع مكون ثقيل الحسابات تحت أب تتغير حالته مع كل ضغطة مفتاح.
قبل التفكير في أي خطافات تخزين مؤقت، افحص موقع الحالة في شجرة المكونات: إذا كانت هناك حالة سريعة التغير—مثل مسودة ملاحظة أو عداد أحرف أو فتح قائمة صغيرة—لا يحتاجها سوى جزء واحد من الشاشة، فالحل الأمثل هو نقل الحالة لأسفل (Moving State Down) داخل مكون فرعي مستقل.
بمجرد انتقال الحالة داخل <QuickNoteBox />، تقتصر إعادة التصيير عليه وحده، فلا يُعاد حساب الجداول الثقيلة المجاورة له مع كل حرف يُكتب.
function QuickNoteBox() {
const [note, setNote] = useState('');
return (
<input
value={note}
onChange={(e) => setNote(e.target.value)}
placeholder="Type a quick note..."
/>
);
}
// Workspace renders <QuickNoteBox /> + <HeavyMetrics />
ماذا لو كانت الحالة السريعة تحيط بالمكون الثقيل نفسه، مثل حاوية تخطيط تغير إطارها اللوني أو تتبع موضع التمرير حول الصفحة كاملة؟ هنا لا يمكن عزل الحالة في مكون منفصل بالأسفل لأن العنصر المحيط ذاته يعتمد عليها.
الحل الأنيق هو فصل الحاوية التفاعلية في مكون غلاف يستقبل children من الأعلى؛ فعندما تتغير حالة الغلاف الداخلي، يظل مرجع children القادم من الأب الخارجي ثابتاً تماماً، فتتخطى React إعادة تصيير المكونات الممررة بداخله تلقائياً!
function AccentShell({ children }) {
const [accent, setAccent] = useState('#7750b2');
return (
<div style={{ borderColor: accent }}>
<button onClick={() => setAccent('teal')}>
Teal
</button>
{children}
</div>
);
}
القاعدة الهندسية الصارمة هي القياس قبل التحسين. تتيح أداة Profiler داخل إضافة React Developer Tools تسجيل تفاعل حقيقي وعرض مخطط اللهب (Flamegraph) حيث تمثل الأشرطة الرمادية مكونات لم يُعَد رسمها، بينما تكشف الأشرطة الصفراء العريضة المكونات البطيئة فعلياً.
كما توفر المكتبة برمجياً مكون <Profiler> المدمج لقياس زمن التركيب والتحديث الفعلي بالمللي ثانية عبر دالة onRender:
import { Profiler } from 'react';
function onRender(id, phase, actualDuration) {
console.log(id, phase, actualDuration.toFixed(2));
}
// Wrap target subtree:
// <Profiler id="List" onRender={onRender} />
التزم دائماً بـ قاعدة تحسين البنية أولاً في مشاريع React: حافظ على نقاء المكونات، وقس التفاعل الفعلي بأداة Profiler أولاً، وطبّق الحلول المعمارية النظيفة مثل خفض الحالة وتمرير children، ولا تنتقل إلى أدوات التذكر اليدوية إلا عند ثبوت الحاجة بالقياس. يلخص الجدول التالي متى تختار كل أسلوب:
| الأسلوب الهندسي | آلية العمل الأساسية | الحالة المثلى للاستخدام |
|---|---|---|
| عزل الحالة بالأسفل | حصر الحالة داخل مكون فرعي صغير ومستقل | عندما يحتاج حقل واحد فقط إلى حالة سريعة التغير |
| التمرير عبر children | الحفاظ على ثبات مرجع عنصر JSX الخارجي | عندما يحيط غلاف تفاعلي بمكونات محتوى ثقيلة |
| أداة القياس Profiler | رصد زمن التصيير الفعلي وسبب تحديث كل مكون | لتشخيص البطء الحقيقي بالبيانات قبل تعديل الكود |
| أدوات التذكر المؤقت | تخزين المكونات أو الحسابات أو الدوال عند ثبات المدخلات | عندما تغذي حالة عليا مشتركة جداول ورسوماً ثقيلة |
ملخص الدرس
حصاد الدرسمراجعة مركّزة لأهم المفاهيم والقواعد الهندسية التي أتقنتها في هذا الدرس قبل التطبيق العملي
ماذا تعلّمت في هذا الدرس؟
تعرفت في هذا الدرس على مسببات إعادة التصيير وانتشارها للأبناء، وصححت مفهوم علاقة الخصائص بالتصيير، وطبقت خفض الحالة وتمرير children وقياس الأداء الفعلي بمكون Profiler. الخطوة التالية: انتقل الآن إلى الدرس رقم 43 «تخطي إعادة التصيير غير الضرورية عبر React.memo» لمواصلة البناء التراكمي المتدرج في مسار React الحديث.
سجّل الدخول لحفظ تقدمك
تابع إنجاز المواضيع والمصطلحات والمهام، وكمّل من آخر خطوة على أي جهاز.
المصطلحات4
راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.
- 01 Re-render إعادة التصيير
- استدعاء React لدالة المكون مجدداً بعد تغير حالة أو سياق لحساب توصيف الواجهة الجديد ومقارنته بالسابق.
- للمراجعة
- 02 Moving State Down عزل الحالة بالأسفل
- نقل الحالة سريعة التغير من المكون الأب الأعلى إلى أصغر مكون فرعي يحتاجها فعلياً لحماية بقية الشجرة.
- للمراجعة
- 03 Flamegraph مخطط اللهب
- مخطط بصري في أداة Profiler يوضح المكونات التي أُعيد رسمها والزمن المستغرق لكل مكون بالمللي ثانية.
- للمراجعة
- 04 Commit Phase مرحلة الاعتماد
- المرحلة التالية لحساب التصيير والتي تطبق فيها React الفروق الفعلية فقط على شجرة عناصر المتصفح.
- للمراجعة
لا توجد بطاقات تطابق البحث والتصفية.
اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.
الاختصارات4
راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.
- 01 DOM DOM
- Document Object Model
- شجرة عناصر المستند في المتصفح والتي تحدث React الأجزاء المتغيرة منها فقط بعد المقارنة.
- للمراجعة
- 02 UI UI
- User Interface
- الواجهة البصرية التفاعلية التي تحافظ React على تطابقها مع الحالة الحالية.
- للمراجعة
- 03 CPU CPU
- Central Processing Unit
- وحدة المعالجة المركزية التي تحاكي أدوات المطورين إبطاءها لاختبار سلاسة الواجهة على الهواتف المتوسطة.
- للمراجعة
- 04 JSX JSX
- JavaScript XML
- الصياغة التي تتحول إلى كائنات عناصر خفيفة تقارنها React بين التصيير السابق والجديد.
- للمراجعة
لا توجد بطاقات تطابق البحث والتصفية.
اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.
مهامك قبل الاختبار
خطوة صغيرة كل مرة. وإنجاز تقدر ترجع له.
-
افتح مثال خفض الحالة في محرر التجريب واكتب عدة جمل بسرعة وتأكد من بقاء عداد تصيير الجدول الثقيل عند الرقم 1.
-
شغّل مثال Profiler وجرّب تصفية العناصر بنصوص مختلفة لملاحظة تغير الطور من mount إلى update وزمن التنفيذ بالمللي ثانية.
تأشير المهمة إقرار منك بإتمامها، وليس تصحيحًا آليًا للكود. يُحفظ تقدمك في حسابك.
اختبر فهمك.
ووصلها للإتقان.
كل سؤال خطوة لقدّام. اختار، اكتب كود، وشوف نتيجتك فورًا.
أكمل المهام، واجمع كل الإجابات الصحيحة. أقل من 100%؟ راجع وأعد المحاولة.
الأسئلة متاحة للاطلاع. سجّل الدخول للتفاعل وحفظ تقدمك.
لمحة عن التحدي10 أسئلة تنتظرك +
بعد التركيب الأولي للمكون، ما الذي يطلق عملية إعادة التصيير في React؟
تبدأ إعادة التصيير عند تغير حالة المكون أو تغير قيمة سياق Context يستهلكه المكون.
افتراضياً في React، إذا أُعيد تصيير المكون الأب فإن المكون الابن العادي الذي لا يستقبل أي خصائص يتخطى إعادة التصيير تلقائياً.
خطأ؛ ففي السلوك الافتراضي تعيد React استدعاء جميع المكونات الأبناء المرسومة داخل الأب حتى لو لم تستقبل أي خاصية.
عندما يحتاج حقل كتابة صغير وحده إلى حالة سريعة التغير بجوار جدول ثقيل، ما الحل الأول الأنسب معمارياً؟
نقل حالة الحقل إلى مكون فرعي مستقل صغير فلا يتأثر الجدول الثقيل المجاور بعمليات الكتابة.
لماذا يتخطى المكون HeavyReport إعادة التصيير عند تحديث الحالة الداخلية للغلاف AccentShell عند تمريره عبر children؟
لأن عنصر JSX الخاص بالمكون الثقيل أُنشئ في الأب الخارجي فيبقى مرجع خاصية children ثابتاً دون تغيير.
تعني إعادة تصيير المكون في React هدم جميع عناصر HTML الحقيقية داخله وإعادة إنشائها من الصفر في المتصفح.
خطأ؛ فإعادة التصيير تعيد استدعاء دالة JavaScript للمقارنة فقط، بينما تعدل React الجزء المتغير فعلياً في DOM.
ما المكون المدمج في React الذي يقيس برمجياً طور التصيير والزمن المستغرق actualDuration؟
يُستخدم المكون المدمج Profiler مع دالة onRender لقياس عدد مرات التصيير وزمنها الفعلي.
في مخطط اللهب Flamegraph داخل أداة React Profiler، علامَ يدل ظهور شريط المكون باللون الرمادي؟
يدل اللون الرمادي على أن هذا المكون لم يُعَد تصييره أصلاً خلال التحديث المسجل.
تُشغّل نسخة التطوير فحوصات إضافية تجعل المكونات تبدو أبطأ مما هي عليه في حزمة الإنتاج الفعلية.
صواب؛ لذا ينبغي التحقق من القياسات النهائية للأداء على نسخة الإنتاج المبنية.
داخل دالة onRender الخاصة بمكون Profiler، لماذا يجب تجنب استدعاء setState بشكل غير مشروط؟
لأن تحديث الحالة عند كل تصيير سيطلق تصييراً جديداً على الفور مما يوقع التطبيق في حلقة لا نهائية.
وفق قاعدة تحسين البنية أولاً، ما الترتيب الهندسي السليم لتحسين أداء مكونات React؟
القياس أولاً بأداة Profiler، ثم تحسين البنية بعزل الحالة أو تمرير children، ثم التذكر اليدوي عند الحاجة.