تصيير القوائم
غالباً ستريد عرض عدة مكونات متشابهة من مجموعة بيانات. يمكنك أن تستخدم دوال المصفوفات الخاصة بلغة JavaScript لتعديل مصفوفة من البيانات. في هذه الصفحة، سوف تستخدم الدالتين الآتيتين: filter()
وmap()
مع مكتبة React لتصفّي وتحول مصفوفتك المكونة من مجموعة بيانات إلى مصفوفة من المكونات.
You will learn
- كيفية تصيير مكونات من مصوفة باستخدام دالة JavaScript
map()
. - كيفية تصيير مكونات محددة فقط باستخدام دالة JavaScript
filter()
. - متى ولماذا تستخدم مفاتيح React (
key
prop)
تصيير البيانات من مصفوفات.
افترض بأنَّ لديك قائمة بالمحتوى.
<ul>
<li>كريولا كاثرين جونسون: عالمة رياضيات</li>
<li>ماريو خوسيه مولينا-باسكيل هنريكيز: كيميائي</li>
<li>محمد عبد السلام: فيزيائي</li>
<li>بيرسي لافون جوليان: كيميائي</li>
<li>سوبراهمانيان تشاندراسيخار: عالم فيزياء الفلك</li>
</ul>
الاختلاف الوحيد بين تلك القوائم هو محتوياتها، أو بالأحرى بياناتها. غالباً ستحتاج إظهار نماذج متعددة من المكون نفسه باستخدام بيانات مختلفة عندما تبني الواجهات: ابتداءً من قوائم من التعليقات إلى معارض صور الملفات الشخصية. في هذه الحالات، يمكنك تخزين تلك البيانات في كائنات ومصفوفات JavaScript واستخدام دالات مثل map()
and filter()
لتصيير قوائم من البيانات من تلك المصفوفات والكائنات.
هذا مثال صغير حول كيفية توليد قائمة عناصر من مصفوفة:
- انقل البيانات إلى مصفوفة:
const people = [
'كريولا كاثرين جونسون: عالمة رياضيات',
'ماريو خوسيه مولينا-باسكيل هنريكيز: كيميائي',
'محمد عبد السلام: فيزيائي',
'بيرسي لافون جوليان: كيميائي',
'سوبراهمانيان تشاندراسيخار: عالم فيزياء الفلك'
];
- استخدم الدالة Map على أفراد القائمة
people
وحولها إلى مصفوفة من عناصر JSX،listItems
:
const listItems = people.map(person => <li>{person}</li>);
- قم بإرجاع القائمة
listItems
من مكونك مغلفة بوسم<ul>
:
return <ul>{listItems}</ul>;
هذه هي النتيجة:
const people = [ 'كريولا كاثرين جونسون: عالمة رياضيات', 'ماريو خوسيه مولينا-باسكيل هنريكيز: كيميائي', 'محمد عبد السلام: فيزيائي', 'بيرسي لافون جوليان: كيميائي', 'سوبراهمانيان تشاندراسيخار: عالم فيزياء الفلك' ]; export default function List() { const listItems = people.map(person => <li>{person}</li> ); return <ul>{listItems}</ul>; }
لاحظ أن sandbox في الأعلى يظهر خطأً في console:
سوف تتعلم كيف تصلح هذا الخطأ لاحقًا في هذه الصفحة. قبل أن نصل إلى ذلك، دعنا نضيف بعض الهيكلية لبياناتك.
تصفية مصفوفات من العناصر
هذه البيانات يمكن أن تكون مهيكلةً أكثر من ذلك.
const people = [{
id: 0,
name: 'كريولا كاثرين جونسون',
profession: 'عالمة رياضيات',
}, {
id: 1,
name: 'ماريو خوسيه مولينا-باسكيل هنريكيز',
profession: 'كيميائي',
}, {
id: 2,
name: 'محمد عبد السلام',
profession: 'فيزيائي',
}, {
id: 3,
name: 'بيرسي لافون جوليان',
profession: 'كيميائي',
}, {
id: 4,
name: 'سوبراهمانيان تشاندراسيخار',
profession: 'عالم فيزياء الفلك',
}];
لنقل أنك تريد طريقة لإظهار الناس الذين مهنتهم هي 'كيميائي'
فقط. تستطيع استخدام دالة JavaScript filter()
لتقوم بإرجاع هؤلاء الناس فقط. هذه دالة تستقبل مصفوفة من العناصر، تمررهم عبر دالة اختبار (وهي دالة تقوم بإرجاع true
أو false
)، وتقوم بإرجاع مصفوفة جديدة من هؤلاء العناصر فقط الذين اجتازوا الاختبار (أي قامت بإرجاع true
)
أنت تريد العناصر التي مهنتها profession
هي كيميائي
فقط. الدالة الاختبارية لهذا الأمر تبدو كالآتي: (person) => person.profession === 'chemist'
. هنا نجد كيفية وضعهم معاً:
- أنشئ مصفوفة جديدة تحوي الناس التي مهنتها
كيميائي
، عن طريق استدعاء الدالةfilter()
على المصفوفةpeople
وتصفيتهم حسب مهنتهمperson.profession === 'كيميائي'
:
const chemists = people.filter(person =>
person.profession === 'كيميائي'
);
- الآن قم بعمل map على المصفوفة
chemists
:
const listItems = chemists.map(person =>
<li>
<img
src={getImageUrl(person)}
alt={person.name}
/>
<p>
<b>{person.name}:</b>
{' ' + person.profession + ' '}
مشهور بـ {person.accomplishment}
</p>
</li>
);
- أخيراً، قم بإرجاع return القائمة
listItems
من مكونك:
return <ul>{listItems}</ul>;
import { people } from './data.js'; import { getImageUrl } from './utils.js'; export default function List() { const chemists = people.filter(person => person.profession === 'chemist' ); const listItems = chemists.map(person => <li> <img src={getImageUrl(person)} alt={person.name} /> <p> <b>{person.name}:</b> {' ' + person.profession + ' '} مشهور بـ {person.accomplishment} </p> </li> ); return <ul>{listItems}</ul>; }
أبقي العناصر مرتبة مع key
لاحظ أنّ كل sandboxes في الأعلى تظهر خطأً في ال console:
أنت تحتاج إعطاء كل عنصر في المصفوفة key
— وهو عبارة عن نص أو معرف فريد يميز العنصر عن العناصر الأخرى في تلك المصفوفة:
<li key={person.id}>...</li>
تُخبر المفاتيح (Keys) React أي عنصر في المصفوفة يتوافق مع كل مكوّن، بحيث يمكنها تطابقها لاحقًا. يصبح ذلك مهمًا إذا كانت عناصر المصفوفة قابلة للتحريك (مثل الترتيب)، أو الإدراج، أو الحذف. تُساعد المفتاح المُختار بشكل جيد React على استنتاج ماذا حدث بالضبط، وإجراء التحديثات الصحيحة على شجرة DOM.
بدلا من توليد مفاتيح بسرعة وإغفالها، يجب عليك تضمينهم في بياناتك:
export const people = [{ id: 0, // يُستخدم في JSX كمفتاح (key) name: 'كريولا كاثرين جونسون', profession: 'عالمة رياضيات', accomplishment: 'حسابات الرحلات الفضائية', imageId: 'MK3eW3A' }, { id: 1, // يُستخدم في JSX كمفتاح (key) name: 'ماريو خوسيه مولينا-باسكيل هنريكيز', profession: 'كيميائي', accomplishment: 'اكتشاف ثقب الأوزون في القطب الشمالي', imageId: 'mynHUSa' }, { id: 2, // يُستخدم في JSX كمفتاح (key) name: 'محمد عبد السلام', profession: 'فيزيائي', accomplishment: 'نظرية المغناطيسية', imageId: 'bE7W1ji' }, { id: 3, // يُستخدم في JSX كمفتاح (key) name: 'بيرسي لافون جوليان', profession: 'كيميائي', accomplishment: 'تطوير أدوية الكورتيزون، الستيرويدات وحبوب منع الحمل', imageId: 'IOjWm71' }, { id: 4, // يُستخدم في JSX كمفتاح (key) name: 'سوبراهمانيان تشاندراسيخار', profession: 'عالم فيزياء الفلك', accomplishment: 'حسابات كتلة نجمة الأبيض القزم', imageId: 'lrWQx8l' }];
Deep Dive
ماذا تفعل عندما يحتاج كل عنصر إلى التصيير إلي عدة عناصر DOM وليس واحداً منها فقط?
الصيغة القصيرة ل <>...</>
Fragment لا تسمح لك بتمرير مفتاح، لذلك تحتاج إمّا أن تجمعهم داخل عنصر <div>
مفرد، أو استخدام الصيغة الطويلة قليلاً و <Fragment>
الأكثر صراحة:
import { Fragment } from 'react';
// ...
const listItems = people.map(person =>
<Fragment key={person.id}>
<h1>{person.name}</h1>
<p>{person.bio}</p>
</Fragment>
);
تختفي Fragments من DOM, لذلك سوف تنتج قائمة منبسطة (لاتحوي قوائم داخلية) مكونة من <h1>
, <p>
, <h1>
, <p>
, إلخ.
من أين تحصل على key
الخاص بك
المصادر المخلتفة للبيانات تقدم مصادر مختلفة للمفاتيح:
- البيانات من قواعد البيانات: إذا كانت بياناتك قادمة من قاعدة بيانات، يمكنك استخدام المفاتيح أو المعرفات الفريدة التي تقدمها قواعد البيانات.
- البيانات التي تم توليدها محلياً: إذا كانت بياناتك مولدة ومستمرة محلياً (مثل: الملاحظات في تطبيق تدوين الملاحظات)، استخدم عداد متزايد،
crypto.randomUUID()
أو حزمة مثلuuid
عندما تنشأ العناصر.
قواعد المفاتيح
- المفاتيح يجب أن تكون فريدة بين الأشقاء. على أي حال،ورغم ذلك، لا مشكلة في استخدام المفاتيح نفسها لعناصر JSX في مصفوفات مختلفة.
- يجب ألا تتغير المفاتيح أو يتم إحباط أهدافها! لا تقم بتوليدهم أثناء التصيير.
لماذا تحتاج React مفاتيح?
تخيل بأنّ الملفات على حاسوبك لا تمتلك أسماء. بدلاً من ذلك أنت ترجع إليهم عن طريق ترتيبهم — الملف الأول، الملف الثاني، إلخ. يمكنك اعتياد ذلك، لكن بمجرد حذفك لملف، يمكن أن يصبح الأمر غير مقبول. الملف الثاني يصبح الملف الاول، الملف الثالث يصبح الملف الثاني، وهكذا.
أسماء الملفات في مجلد ومفاتيح JSX في مصفوفة تخدم نفس الهدف. إنها تمكننا من تحديد عنصر بشكل فريد بين أشقائه. الاختيار الجيد للمفتاح يقدم معلومات أكثر من الموضع خلال المصفوفة. وحتى لو تغير الموضع بسبب إعادة الترتيب، ال key
يمكن React من تحديد العنصر أثناء وجوده.
Recap
تعلمت في هذه الصفحة:
- كيف تحول البيانات إلى مكونات أو إلى هياكل مثل المصفوفات والكائنات.
- كيف تولد مجموعات من المكونات المتشابهة باستخدام دالة JavaScript
map()
. - كيف تنشئ مصفوفات من عناصر مصفّاة باستخدام دالة JavaScript
filter()
. - لماذا وكيف تضبط ال
key
لكل مكون في مجموعة بطريقة تستطيع فيها React أن تتعقب كل واحد منهم حتى لو تغيرت بياناتهم ومواضعهم.
Challenge 1 of 4: فصل قائمة في قائمتين
هذا المثال يظهر قائمة بجميع الناس.
أجري تغيرات عليها إظهار قائمتين منفصلتين واحدة بعد اأخرى: Chemists وEveryone Else. مثل ما سبق, يمكنك تحديد فيما إذا كان الشخص عالم كيمياء عن طريق التحقق من صحة person.profession === 'chemist'
.
import { people } from './data.js'; import { getImageUrl } from './utils.js'; export default function List() { const listItems = people.map(person => <li key={person.id}> <img src={getImageUrl(person)} alt={person.name} /> <p> <b>{person.name}:</b> {' ' + person.profession + ' '} known for {person.accomplishment} </p> </li> ); return ( <article> <h1>Scientists</h1> <ul>{listItems}</ul> </article> ); }