تصيير القوائم
غالباً ستريد عرض عدة مكونات متشابهة من مجموعة بيانات. يمكنك ان تستخدم دوال المصفوفات الخاصة بلغة JavaScript لكي تضاعف مصفوفة من البيانات. في هذه الصفحة، سوف تستخدم الدالتين الآتيتين: filter()
و map()
مع مكتبة React لتصفّي و تحول مصفوفتك المكونة من مجموعة بيانات إلى مصفوفة من المكونات.
You will learn
- كيف يمكنك تصيير مكونات من مصوفة باستخدام دالة JavaScript
map()
. - كيف يمكنك تصيير مكونات محددة فقط باستخدام دالة JavaScript
filter()
. - متى ولماذا تستخدم مفاتيح React.
تصيير البيانات من مصفوفات.
افترض بأنَّ لديك قائمة بالمحتوى.
<ul>
<li>Creola Katherine Johnson: mathematician</li>
<li>Mario José Molina-Pasquel Henríquez: chemist</li>
<li>Mohammad Abdus Salam: physicist</li>
<li>Percy Lavon Julian: chemist</li>
<li>Subrahmanyan Chandrasekhar: astrophysicist</li>
</ul>
الاختلاف الوحيد بين تلك القوائم هو محتوياتها، أو بالأحرى بياناتها. غالباً ستحتاج إظهار نماذج من المكون نفسه باستخدام بيانات مختلفة عندما تبني الواجهات: ابتداءً من قوائم من التعليقات إلى معارض من صور الملفات الشخصية. في هذه الحالات، يمكنك تخزين تلك البيانات في كائنات و مصفوفات JavaScript واستخدام دالات مثل map()
and filter()
لتصيير قوائم من البيانات من تلك المصفوفات والكائنات.
هذا مثال صغير حول كيفية توليد قائمة عناصر من مصفوفة:
- انقل البيانات إلى مصفوفة:
const people = [
'Creola Katherine Johnson: mathematician',
'Mario José Molina-Pasquel Henríquez: chemist',
'Mohammad Abdus Salam: physicist',
'Percy Lavon Julian: chemist',
'Subrahmanyan Chandrasekhar: astrophysicist'
];
- استخدم الدالة Map على أفراد القائمة
people
وحولها إلى مصفوفة من JSX عقد,listItems
:
const listItems = people.map(person => <li>{person}</li>);
- قم بأرجاع القائمة
listItems
من مكونك مغلفة بوسم<ul>
:
return <ul>{listItems}</ul>;
هذه هي النتيجة:
const people = [ 'Creola Katherine Johnson: mathematician', 'Mario José Molina-Pasquel Henríquez: chemist', 'Mohammad Abdus Salam: physicist', 'Percy Lavon Julian: chemist', 'Subrahmanyan Chandrasekhar: astrophysicist' ]; export default function List() { const listItems = people.map(person => <li>{person}</li> ); return <ul>{listItems}</ul>; }
لاحظ sandbox في الأعلى يظهر خطأً في console:
سوف تتعلم كيف تصلح هذا الخطأ لاحقأً في هذه الصفحة. قبل أن نصل إلى ذلك، دعنا نضيف بعض الهيكلية لبياناتك.
تصفية مصفوفات من العناصر
هذه البيانات يمكن أن تكون مهيكلةً أكثر من ذلك.
const people = [{
id: 0,
name: 'Creola Katherine Johnson',
profession: 'mathematician',
}, {
id: 1,
name: 'Mario José Molina-Pasquel Henríquez',
profession: 'chemist',
}, {
id: 2,
name: 'Mohammad Abdus Salam',
profession: 'physicist',
}, {
name: 'Percy Lavon Julian',
profession: 'chemist',
}, {
name: 'Subrahmanyan Chandrasekhar',
profession: 'astrophysicist',
}];
دعنا نقول بأنك تريد طريقة لإظهار الناس الذين مهنتهم هي 'chemist'
فقط. تستطيع استخدام دالة JavaScript filter()
لتقوم بإرجاع هؤلاء الناس فقط. هذه دالة تستقبل مصفوفة من العناصر، تمررهم عبر “test” (وهي دالة تقوم بإرجاع true
أو false
), وتقوم بإرجاع مصفوفة جديدة من هؤلاء العناصر فقط الذين اجتازوا الاختبار “الدالة test” (أي قامت بإرجاع true
)
أنت تريد العناصر التي مهنتها profession
هي chemist
فقط. الدالة “test” لهذا الأمر تبدو كالآتي: (person) => person.profession === 'chemist'
. هنا نجد كيفية وضعهم معاً:
- أنشئ مصفوفة جديدة تحوي الناس التي مهنتها “chemist” أو “عالم كيمياء” فقط,
chemists
, عن طريق استدعاء الدالةfilter()
على المصفوفةpeople
وتصفيتهم حسب مهنتهمperson.profession === 'chemist'
:
const chemists = people.filter(person =>
person.profession === 'chemist'
);
- الآن قم بغمل map على المصفوفة
chemists
:
const listItems = chemists.map(person =>
<li>
<img
src={getImageUrl(person)}
alt={person.name}
/>
<p>
<b>{person.name}:</b>
{' ' + person.profession + ' '}
known for {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 + ' '} known for {person.accomplishment} </p> </li> ); return <ul>{listItems}</ul>; }
أبقي العناصر مرتبة مع key
لاحظ بأنّ كل snaboxes في الأعلى تظهر خطأً في ال console:
أنت تحتاج إعطاء كل عنصر في المصفوفة key
— نوهو عبارة عن نص أو فريد يميز العنصر عن العناصر الأخرى في تلك المصفوفة:
<li key={person.id}>...</li>
المفاتيح تخبر React بكل عنصر في المصفوفة مع المكون الموافق له، لذلك يصبح بإمكانها أن تجدهم لاحقاً. هذا الأمر يصبح بالغ الأهمية إذا استطاعت عناصر مصفوفتك التحرك (مثال ذلك الفرز)، أو إدخال عناصر أخرى، أو حذف عناصر من المصفوفة. الاختيار الجيد لل key
يساعد React على استنتاج ما حدث بالضبط، وبالتالي القيام بالتحديثات الصحيحة على شجرة DOM.
بدلا من توليد مفاتيح بسرعة وإغفالها، يجب عليك تضمينهم في بياناتك:
export const people = [{ id: 0, // Used in JSX as a key name: 'Creola Katherine Johnson', profession: 'mathematician', accomplishment: 'spaceflight calculations', imageId: 'MK3eW3A' }, { id: 1, // Used in JSX as a key name: 'Mario José Molina-Pasquel Henríquez', profession: 'chemist', accomplishment: 'discovery of Arctic ozone hole', imageId: 'mynHUSa' }, { id: 2, // Used in JSX as a key name: 'Mohammad Abdus Salam', profession: 'physicist', accomplishment: 'electromagnetism theory', imageId: 'bE7W1ji' }, { id: 3, // Used in JSX as a key name: 'Percy Lavon Julian', profession: 'chemist', accomplishment: 'pioneering cortisone drugs, steroids and birth control pills', imageId: 'IOjWm71' }, { id: 4, // Used in JSX as a key name: 'Subrahmanyan Chandrasekhar', profession: 'astrophysicist', accomplishment: 'white dwarf star mass calculations', 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
الخاص بك
المصادر المخلتفة للبيانات تقدم مصادر مختلفة للمفاتيح:
- البيانات من قواعد البيانات: إذا كانت بياناتك قادمة من قاعدة بيانات، يمكنك استخدام keys/IDs الخاصة بقاعدة البيانات, والتي هي فريدة بطبيعتها.
- البيانات التي تم توليدها محلياً: إذا كانت بياناتك مولدة ومستمرة محلياً (الملاحظات في تطبيق تدوين الملاحظات)، تستخدم عداد متزايد،
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> ); }