یکی از کارهای بسیار رایج در وب، نمایش مجموعهای از دادههای مشابه (مثل لیست کامنتها، محصولات یا کارتهای پروفایل) است. در React شما نیازی به یادگیری سینتکس جدیدی برای حلقهها ندارید؛ بلکه با استفاده از متدهای بومی جاوااسکریپت یعنی map و filter آرایههای خام داده را به آرایهای از کامپوننتهای زنده تبدیل میکنید.
تبدیل یک آرایه به المانهای رابط کاربری با متد map()
فیلتر کردن اطلاعات و نمایش موارد خاص با متد filter()
مفهوم حیاتی key و دلیل نیاز ریاکت به آن
map()فرض کنید لیست متنی زیر را در اختیار دارید:
کرولا کاترین جانسون: ریاضیدان
ماریو خوزه مولینا: شیمیدان
محمد عبدالسلام: فیزیکدان
تنها تفاوت این آیتمها، دادههای درون آنهاست. برای رندر خودکار این ساختار در راکت، دادهها را به یک آرایه منتقل کرده و روی آن حلقه میزنیم:
// ۱. انتقال دادهها به آرایه جاوااسکریپتی
const people = [
'کرولا کاترین جانسون: ریاضیدان',
'ماریو خوزه مولینا: شیمیدان',
'محمد عبدالسلام: فیزیکدان'
];
export default function List() {
// ۲. نگاشت (Map) اعضای آرایه به گرههای JSX
const listItems = people.map(person =>
<li>{person}</li>
);
// ۳. بازگرداندن کل لیست درون یک تگ والد
return <ul>{listItems}</ul>;
}
اگر کدهای بالا را اجرا کنید، در بخش کنسول (Console) مرورگر با یک اخطار (Warning) قرمز رنگ مواجه خواهید شد:
Warning: Each child in a list should have a unique "key" prop. (هر فرزند در یک لیست باید یک پروپ "key" منحصربهفرد داشته باشد).
کمی جلوتر یاد میگیریم چطور این اخطار را برطرف کنیم.
filter()بیایید دادههایمان را ساختاریافتهتر کنیم و به شکل آرایهای از اشیاء (Objects) درآوریم. حالا فرض کنید میخواهیم فقط دانشمندانی که حرفه آنها «شیمیدان» (chemist) است را در صفحه نشان دهیم:
const people = [{
id: 0,
name: 'ماریو خوزه مولینا',
profession: 'chemist',
}, {
id: 1,
name: 'محمد عبدالسلام',
profession: 'physicist',
}, {
id: 2,
name: 'پرسی لاون جولیان',
profession: 'chemist',
}];
با ترکیب متد filter() (برای جداسازی) و متد map() (برای رندر خروجی)، این کار را انجام میدهیم:
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}
</p>
</li>
);
return <ul>{listItems}</ul>;
}
⚠️ یک تله سینتکسی در توابع پیکانی (Arrow Functions): > توابع پیکانی اگر در یک خط نوشته شوند، خروجی بعد از
=>را به صورت خودکار برگشت میدهند (Implicit Return). اما اگر بعد از=>از آکولااد{}استفاده کنید، بدنه تابع بلوکی میشود و حتماً باید کلمه کلیدیreturnرا صراحتاً بنویسید؛ در غیر این صورت خروجی شما کاملاً خالی رندر میشود!const listItems = chemists.map(person => { // باز شدن آکولااد یعنی بدنه بلوکی return <li>{person.name}</li>; // نوشتن کلمه return اجباری است! });
keyبرای برطرف کردن اخطار کنسول، باید به هر آیتم در آرایه یک پروپ به نام key اختصاص دهید. این کلید میتواند یک رشته متنی یا یک عدد باشد که آن آیتم را در میان همسایگانش کاملاً متمایز کند:
const listItems = people.map(person =>
<li key={person.id}> {/* پروپ کلید دقیقا روی داخلیترین تگ حلقه قرار میگیرد */}
{person.name}
</li>
);
تصور کنید پوشههای روی دسکتاپ شما هیچ نامی نداشتند و شما آنها را بر اساس ترتیبشان صدا میزدید: پوشه اول، پوشه دوم و... . تا زمانی که پوشهای حذف نشود همهچیز خوب است، اما به محض حذف پوشه دوم، پوشه سوم تبدیل به پوشه دوم میشود و کل محاسبات ذهن شما به هم میریزد!
پروپ key در واقع نقش «نامِ شناساییِ» المان را برای ریاکت بازی میکند. اگر آیتمها به خاطر مرتبسازی، حذف یا اضافه شدن جابهجا شوند، ریاکت با نگاه کردن به این کلیدِ پایدار، دقیقاً میفهمد چه اتفاقی برای کدام المان افتاده است و به جای بازسازی کل ساختار، فقط همان بخش از DOM مرورگر را بهروزرسانی میکند.
کلیدها باید در میان همسایگان خود یکتا باشند: نیازی نیست کلیدها در کل پروژه تک باشند؛ داشتن کلیدهای مشابه در دو آرایه کاملاً متفاوت هیچ ایرادی ندارد.
کلیدها نباید تغییر کنند: هرگز کلیدها را در زمان رندر و به صورت آنی تولید نکنید (مثلاً با کدهایی مثل key={Math.random()}). این کار باعث میشود در هر بار بهروزرسانی صفحه، کلید جدیدی ساخته شود، ریاکت المان قبلی را کاملاً نابود کند و از نو بسازد که علاوه بر افت شدید سرعت، باعث پاک شدن اطلاعات وارد شده توسط کاربر در فرمها میشود.
⚠️ تله بزرگ: استفاده از Index آرایه به عنوان Key اگر خودتان کلیدی مشخص نکنید، ریاکت به صورت پیشفرض از شماره ردیف (Index) المان در آرایه استفاده میکند. اما استفاده از Index به عنوان کلید، یک ضدالگو (Anti-pattern) است! اگر لیست شما مرتبسازی مجدد شود، یا ردیفی از وسط آن حذف شود، این شاخصها تغییر کرده و باگهای بسیار ظریف، عجیب و سختی را در ظاهر برنامهتان ایجاد میکنند. همیشه سعی کنید از شناسه پایدارِ دادهها (مانند
idدیتابیس یا تولید شناسه با پکیجهایی مثلuuid) استفاده کنید.
اگر در حلقه map() نیاز دارید برای هر آیتم چند تگ همسایه (مثلاً یک <h1> و یک <p>) بدون تگ والد <div> رندر کنید، تگهای کوتاه Fragment (<>...</>) به شما اجازه پاس دادن پروپ key را نمیدهند. برای حل این مشکل، باید فرم کامل و رسمی <Fragment> را امپورت کرده و کلید را روی آن بچسبانید:
import { Fragment } from 'react';
const listItems = people.map(person =>
<Fragment key={person.id}>
<h1>{person.name}</h1>
<p>{person.profession}</p>
</Fragment>
);
دادههای خام را به ساختارهای پویای آرایهای منتقل کنید تا نگهداری آنها آسان شود.
با کمک متد map() مجموعهای از کامپوننتهای همشکل اما با دادههای متفاوت خلق کنید.
با کمک متد filter() آرایههای خود را بر اساس شروط خاص غربال کنید.
پروپ key یک راهنمای حیاتی برای ریاکت است تا تغییرات، جابهجاییها و حذفیات اعضای یک لیست را بدون خطا و با سرعت بالا مدیریت کند.
این محتوا کاملا رایگان توسط تیم کدلپر ترجمه شده و در اختیار شما کاربران عزیز قرار گرفته است، هر گونه کپی برداری برای مقاصد غیر رایگان و بدون ذکر منبع، مورد پیگیری قانونی قرار میگیرد.
ترجمه شده از منبع: https://react.dev/learn