في هذا الدرس 6تصفّح المواضيع
نادراً ما تكتفي تطبيقات React العملية بمصفوفات ثابتة مكتوبة يدوياً داخل الكود؛ بل تتصل لوحات التحكم ومنصات الدورات والمتاجر بواجهات برمجية خلفية لجلب بيانات JSON محدثة عبر الشبكة. يسير جلب البيانات في المتصفح وفق أربع خطوات متتابعة ومنظمة: تهيئة الحالة بقيمة ابتدائية آمنة مثل useState([])، ورسم الواجهة المبدئية فوراً دون تجميد الشاشة، ثم إطلاق طلب الشبكة داخل useEffect() بعد اعتماد العناصر في DOM، وأخيراً استدعاء دالة تحديث الحالة فور وصول الرد لإعادة رسم البطاقات تلقائياً.
يُمنع تماماً استدعاء fetch() مباشرة في جسم دالة المكون أثناء التصيير؛ لأن تحديث الحالة بعد وصول الرد سيعيد استدعاء المكون فيدخل التطبيق في حلقة طلبات لا نهائية.
useEffect(() => {
async function loadCourses() {
const res = await fetch('/api/courses');
const data = await res.json();
setCourses(data);
}
loadCourses();
}, []);
يقع كثير من المبتدئين في خطأ وسم دالة التأثير نفسها بالكلمة المفتاحية async عبر كتابة useEffect(async () => { ... }, []). في لغة JavaScript تعيد أي دالة async كائن وعد Promise تلقائياً، في حين تشترط React أن تعيد دالة useEffect() إما قيمة فارغة undefined أو دالة تنظيف متزامنة تستدعيها المكتبة عند إزالة المكون.
للاستفادة من وضوح صياغة async/await دون الإخلال بعقد التأثير، اترك الدالة الخارجية متزامنة وعرّف بداخلها دالة async function loadData() ثم استدعها مباشرة.
تختلف دالة المتصفح القياسية fetch() عن بعض المكتبات الخارجية في تفصيل جوهري: فهي لا ترفض الوعد تلقائياً عندما يرد الخادم برمز خطأ بروتوكولي مثل 404 Not Found أو 500. فطالما وصلت رؤوس HTTP عبر الشبكة بنجاح، تعتبر fetch() الاتصال مكتملاً، ومحاولة تمرير الرد مباشرة إلى عناصر العرض قد تضع كائن خطأ مكان مصفوفة البيانات.
تحقق دائماً من الخاصية المنطقية response.ok (وتكون true فقط لرموز النجاح بين 200 و299) فور انتهاء الطلب، وارمِ استثناءً واضحاً عبر throw new Error() عند فشلها قبل قراءة response.json().
const res = await fetch(`/api/courses/${courseId}`);
if (!res.ok) {
throw new Error(`HTTP status ${res.status}`);
}
const item = await res.json();
setCourse(item);
يكفي تمرير مصفوفة اعتماديات فارغة [] عندما نحتاج إلى جلب البيانات مرة واحدة عند ظهور المكون. أما إذا اعتمد عنوان الطلب على خاصية ممررة مثل category أو حالة تصفية مثل searchQuery، فيجب إدراج جميع هذه القيم التفاعلية في مصفوفة الاعتماديات [category, searchQuery].
بمجرد تغيير المستخدم للتصنيف، ترصد React اختلاف القيمة وتعيد تشغيل التأثير تلقائياً لجلب القائمة المطابقة. احرص دائماً على تمرير المعاملات المتغيرة داخل encodeURIComponent() حتى لا تؤدي المسافات أو الرموز الخاصة مثل & إلى إفساد رابط الطلب.
useEffect(() => {
async function loadByCategory() {
const q = encodeURIComponent(category);
const url = `/api/courses?category=${q}`;
const res = await fetch(url);
if (res.ok) setCourses(await res.json());
}
loadByCategory();
}, [category]);
فور استلام مصفوفة الكائنات من الخادم، حوّل كل سجل إلى عناصر واجهة دلالية واضحة مع إسناد المعرّف الفريد القادم من قاعدة البيانات إلى خاصية المفتاح key={product.id}، وتجنب الاعتماد على فهرس المصفوفة الرقمي في القوائم القابلة للتصفية أو التحديث.
نسّق القيم الخام أثناء العرض مثل تحويل الأرقام إلى أسعار مقروءة والقيم المنطقية إلى شارات توفر واضحة، بحيث لا تطبع القيم البرمجية المجردة مباشرة للمستخدم.
{products.map((item) => (
<article key={item.id} className="rx-row">
<strong>{item.name}</strong>
<span>${item.price}</span>
<span>{item.inStock ? 'In Stock' : 'Out'}</span>
</article>
))}
قد ينقطع اتصال الشبكة فجأة أو يتأخر الخادم أو يصل رد غير صالح للتحليل؛ ولذلك يضمن تغليف عملية الجلب كاملة داخل بنية try / catch / finally اصطياد أي استثناء بأمان بدلاً من ترك وعود مرفوضة غير معالجة في المتصفح.
داخل كتلة catch نحدّث حالة الخطأ برسالة مفهومة ليبقى المكون متماسكاً، وداخل finally ننهي حالة الانتظار سواء نجح الطلب أم تعذر. يوضح الجدول التالي خلاصة القواعد الهندسية لجلب البيانات:
| مرحلة الجلب | النمط الخاطئ الشائع | المعيار الهندسي في React |
|---|---|---|
| موضع الاستدعاء | تشغيل fetch<code>() مباشرة أثناء التصيير | تشغيل fetch<code>() داخل useEffect<code>() بعد الرسم الأولي |
| صياغة الدالة غير المتزامنة | وضع async مباشرة على معامل useEffect | تعريف دالة async داخلية واستدعاؤها بوضوح |
| فحص حالة البروتوكول | افتراض رفض الوعد تلقائياً عند خطأ 404 | فحص response.ok صراحة قبل قراءة response.json<code>() |
| تحديث المعاملات | إهمال متغيرات التصفية من مصفوفة الاعتماديات | إدراج [category, query] مع ترميز encodeURIComponent<code>() |
ملخص الدرس
حصاد الدرسمراجعة مركّزة لأهم المفاهيم والقواعد الهندسية التي أتقنتها في هذا الدرس قبل التطبيق العملي
ماذا تعلّمت في هذا الدرس؟
أتقنت في هذا الدرس دورة جلب البيانات داخل مكونات React عبر تشغيل الطلبات في useEffect بدالة async داخلية، وفحص response.ok قبل تحليل JSON، وإعادة الجلب التلقائية عند تغير المعاملات، وتنسيق السجلات بمفاتيح مستقرة مع اصطياد أعطال الشبكة بأمان. الخطوة التالية: انتقل الآن إلى الدرس رقم 38 «إدارة حالات التحميل والخطأ والبيانات الفارغة» لمواصلة البناء التراكمي المتدرج في مسار React الحديث.
سجّل الدخول لحفظ تقدمك
تابع إنجاز المواضيع والمصطلحات والمهام، وكمّل من آخر خطوة على أي جهاز.
المصطلحات4
راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.
- 01 Client-Side Fetching الجلب من جهة العميل
- طلب بيانات JSON من الخادم مباشرة من المتصفح بعد تركيب الهيكل المبدئي لمكون React.
- للمراجعة
- 02 Response Status Guard حارس حالة الاستجابة
- التحقق من قيمة response.ok لضمان وقوع رمز HTTP بين 200 و299 قبل تحليل محتوى الرد.
- للمراجعة
- 03 Reactive Dependency الاعتمادية التفاعلية
- خاصية أو حالة تُدرج في مصفوفة اعتماديات useEffect لإعادة جلب البيانات تلقائياً عند تغيرها.
- للمراجعة
- 04 Payload Serialization تحليل حمولة البيانات
- تحويل النص الخام القادم بصيغة JSON عبر الشبكة إلى كائنات ومصفوفات JavaScript بواسطة response.json().
- للمراجعة
لا توجد بطاقات تطابق البحث والتصفية.
اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.
الاختصارات4
راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.
- 01 API API
- Application Programming Interface
- واجهة برمجية منظمة تتيح لمكونات الواجهة الأمامية تبادل البيانات مع الخوادم الخلفية.
- للمراجعة
- 02 REST REST
- Representational State Transfer
- نمط معماري قياسي للويب ينظم موارد الخادم عبر عناوين واضحة وأفعال بروتوكول HTTP.
- للمراجعة
- 03 JSON JSON
- JavaScript Object Notation
- صيغة نصية خفيفة وقياسية تُستخدم لتبادل السجلات المهيكلة بين الخادم والمتصفح.
- للمراجعة
- 04 URI URI
- Uniform Resource Identifier
- سلسلة نصية قياسية تحدد عنوان المورد على الشبكة ومعاملات الاستعلام المرمّزة الخاصة به.
- للمراجعة
لا توجد بطاقات تطابق البحث والتصفية.
اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.
مهامك قبل الاختبار
خطوة صغيرة كل مرة. وإنجاز تقدر ترجع له.
-
افتح مثال CourseInspector في محرر التجريب وجرّب الأزرار الصحيحة وزر المعرّف غير الموجود 404 لملاحظة كيف تحمي response.ok حالة المكون.
-
افتح مثال FilteredCourses في محرر التجريب وبدّل التصنيفات ثم اعرض عدد الدروس course.lessons بجانب اسم كل دورة.
تأشير المهمة إقرار منك بإتمامها، وليس تصحيحًا آليًا للكود. يُحفظ تقدمك في حسابك.
اختبر فهمك.
ووصلها للإتقان.
كل سؤال خطوة لقدّام. اختار، اكتب كود، وشوف نتيجتك فورًا.
أكمل المهام، واجمع كل الإجابات الصحيحة. أقل من 100%؟ راجع وأعد المحاولة.
الأسئلة متاحة للاطلاع. سجّل الدخول للتفاعل وحفظ تقدمك.
لمحة عن التحدي10 أسئلة تنتظرك +
لماذا يُمنع استدعاء fetch() مباشرة في جسم دالة المكون أثناء التصيير في المتصفح؟
لأن تحديث الحالة بعد وصول الرد يعيد تصيير المكون فيطلق طلباً جديداً في حلقة لا نهائية.
تمرير دالة async مباشرة إلى useEffect يخالف قواعد React لأن دالة async تعيد دائماً كائن Promise بدلاً من دالة تنظيف.
صواب؛ يجب تعريف دالة async داخلية داخل دالة التأثير المتزامنة ثم استدعاؤها.
كيف تتصرف دالة fetch() القياسية في المتصفح عندما يرد الخادم برمز الخطأ HTTP 404؟
يكتمل الوعد بشكل عادي وتكون قيمة response.ok مساوية لـ false، ولا يُرفض تلقائياً.
ما نطاق رموز حالة HTTP الذي يجعل الخاصية response.ok تساوي true؟
تكون الخاصية response.ok صحيحة حصراً لرموز النجاح الواقعة بين 200 و299.
إذا كان التأثير يجلب البيانات بناءً على المتغير category، فماذا يجب أن نضع في مصفوفة الاعتماديات؟
نضع [category] لكي تعيد React تنفيذ طلب الجلب تلقائياً كلما تغيرت قيمة التصنيف.
تغليف نصوص البحث المدخلة بدالة encodeURIComponent() يمنع المسافات والرمز & من إفساد بنية رابط الطلب.
صواب؛ فالترميز القياسي يحافظ على سلامة معاملات الاستعلام في الرابط.
ما القيمة الابتدائية الأكثر أماناً لحالة تخزن قائمة منتجات ستُعرض عبر دالة .map()؟
المصفوفة الفارغة [] تسمح بتنفيذ .map() بأمان تام في الرسم الأولي قبل وصول البيانات.
ما القيمة الصحيحة التي ينبغي إسنادها لخاصية المفتاح key عند عرض سجلات قادمة من الخادم؟
يُستخدم المعرّف الفريد والمستقر القادم مع كل سجل مثل item.id.
استدعاء response.json() يعيد كائن وعد Promise، لذا يلزم انتظاره بـ await قبل تمرير البيانات إلى دالة تحديث الحالة.
صواب؛ لأن قراءة جسم الاستجابة وتحويله إلى كائنات عملية غير متزامنة.
لماذا يغلف المهندسون عمليتي الجلب وتحليل JSON داخل كتلة try / catch / finally؟
لاصطياد انقطاع الشبكة أو أخطاء الاستجابة بأمان ومنع توقف الواجهة أو بقاء التحميل معلقاً.