الوحدة 2 · الـ Components والـ Props
عرض القوائم باستخدام الـ keys
22 دقراءة 4 دبيئة تجريب الكود
الدرس في لمحة
اعرض القوائم من المصفوفات باستخدام map، وصفِّها ورتّبها من دون تعديل البيانات، واختر keys تحافظ على هوية كل عنصر وعلى الـ state الخاص به بين مرّات الـ render.
- 1من البيانات إلى العناصر باستخدام map
- 2ما وظيفة الـ keys
- 3اختيار الـ key
- 4الـ keys على الـ components والـ fragments
لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.
Watchlist قائمة. وكذلك صفحة المنشورات، وجدول الطلبات، ونتائج البحث، والقائمة الرئيسية. أغلب الواجهات قوائم من أشياء مبنية من مصفوفات بيانات، ونهج React هو ما قد تخمّنه من JavaScript نفسها: حوّل مصفوفة البيانات إلى مصفوفة عناصر.
من البيانات إلى العناصر باستخدام map
export default function MovieList({ movies }) {
return (
<ul>
{movies.map((movie) => (
<li key={movie.id}>
{movie.title} ({movie.year})
</li>
))}
</ul>
);
}تُرجع map مصفوفة من عناصر <li>، وتعرض React المصفوفات بعرض كل عنصر فيها بالترتيب. لا توجد صياغة حلقات خاصة لتتعلّمها؛ إنها دالة المصفوفات التي تعرفها أصلًا.
والتصفية والترتيب الفكرة نفسها: جهّز المصفوفة، ثم طبّق عليها map. افعل ذلك أثناء الـ render، من البيانات التي لديك. القائمة الظاهرة مشتقّة، فلا تحتاج إلى أن تكون state.
const movies = [
{ id: 'a1', title: 'Arrival', year: 2016, watched: true },
{ id: 'p2', title: 'Past Lives', year: 2023, watched: false },
{ id: 'd3', title: 'Dune: Part Two', year: 2024, watched: false },
];
const toWatch = movies
.filter((m) => !m.watched)
.toSorted((a, b) => b.year - a.year);
console.log(toWatch.map((m) => m.title)); // ["Dune: Part Two", "Past Lives"]
console.log(movies[0].title); // Arrival (the original order is untouched)تُرجع toSorted نسخة مرتّبة، وهي مدعومة في كل المتصفّحات الحالية. أمّا sort الأقدم فتعيد ترتيب المصفوفة في مكانها. وإذا استُدعيت على state أو props، فهي تعدّل بصمت بيانات لا تملكها. وإن احتجت إلى دعم متصفّحات أقدم، فانسخ أولًا: [...movies].sort(…).
ما وظيفة الـ keys
كل عنصر في قائمة يحتاج إلى prop اسمه key، وتحذّرك React في الـ console حين يغيب. ويتّضح السبب حين تتغيّر القائمة.
حين تعيد React رسم قائمة، تكون لديها مصفوفة العناصر القديمة والجديدة. وعليها أن تطابق بينهما: أي عنصر جديد هو نفسه أي عنصر قديم؟ هذا مهمّ لأن كل عنصر قد يملك state، مثل ملاحظة نصف مكتوبة في حقل، أو زر عليه التركيز، أو قائمة مفتوحة، ويجب أن يبقى هذا الـ state مع العنصر الصحيح.
الـ key هو بطاقة اسم العنصر. تطابق React العناصر القديمة والجديدة حسب الـ key. الـ key نفسه: إنه العنصر نفسه، فتحتفظ React بالـ DOM والـ state الخاصين به وتحدّث ما تغيّر. key جديد: عنصر جديد، فتُنشئه React. key غائب: أُزيل العنصر، فتهدمه React.
اختيار الـ key
الـ key الجيد فريد بين الإخوة وثابت: للعنصر نفسه الـ key نفسه في كل render.
- استخدم معرّفًا من بياناتك. صفوف قاعدة البيانات وكائنات الـ API لها معرّف أصلًا.
- أنشئ المعرّفات حين تُنشأ العناصر. للأفلام المضافة عبر نموذج، ولّد المعرّف في المعالج الذي يضيفها:
{ id: crypto.randomUUID(), title, year }. يُخزَّن على الكائن ولا يتغيّر أبدًا. - لا تولّد الـ keys أثناء الـ render أبدًا.
key={Math.random()}أوkey={crypto.randomUUID()}داخلmapينتج keys جديدة في كل render. فتعامل React كل صف على أنه جديد تمامًا، وتهدم الـ DOM، وتُضيّع تركيز الحقل والـ state مع كل حرف تكتبه. - لا تستخدم محتوى غير فريد. العناوين تتكرّر؛ هناك عدّة أفلام اسمها “Dune”.
لا يلزم أن تكون الـ keys فريدة إلا بين الإخوة في القائمة نفسها. ويمكن لقائمتين مختلفتين استخدام المعرّفات نفسها.
الـ keys على الـ components والـ fragments
يوضع الـ key على العنصر الخارجي الذي تُرجعه دالة الـ callback في map. وحين يكون ذلك component، ضعه على الـ component:
{movies.map((movie) => (
<MovieItem key={movie.id} movie={movie} />
))}لا يستطيع MovieItem قراءة key؛ فـ React تستخدمه ولا تمرّره إلى الأسفل. وإذا احتاج الـ component إلى المعرّف، فمرّره بشكل منفصل كـ prop.
وحين يرسم كل عنصر عدّة إخوة من دون غلاف، استخدم الصيغة الطويلة للـ fragment، فهي تقبل key:
import { Fragment } from 'react';
{movies.map((movie) => (
<Fragment key={movie.id}>
<dt>{movie.title}</dt>
<dd>{movie.year}</dd>
</Fragment>
))}الصيغة القصيرة <>…</> لا تقبل key.
صار بإمكانك عرض أي قائمة بشكل صحيح. وبهذا يكتمل Watchlist الثابت. في القسم التالي يبدأ بالحركة: الـ state يتيح للقائمة أن تتغيّر حين ينقر المستخدم ويكتب ويرسل.
أهم النقاط
- حوّل مصفوفة البيانات إلى مصفوفة عناصر باستخدام
map، وضع الـkeyعلى العنصر الخارجي الذي تُرجعه دالة الـ callback. - يُخبر الـ key React بهوية كل عنصر بين مرّات الـ render، لذا يجب أن يكون فريدًا بين الإخوة وثابتًا مع الوقت.
- استخدم معرّفًا (id) من بياناتك كـ key؛ وأنشئ المعرّفات لحظة إنشاء العناصر، لا أثناء الـ render أبدًا.
- الـ keys المبنية على الـ index تنكسر حين يمكن إعادة ترتيب القائمة أو تصفيتها أو الإدراج فيها، لأن الـ state يلتصق بالموضع بدل العنصر.
- صفِّ نُسخًا من بياناتك ورتّبها أثناء الـ render؛ فالدالة
sortتغيّر المصفوفة في مكانها، لذا استخدمtoSortedأو رتّب نسخة.