چگونه آرایه ای از کامپوننت ها را در React رندر کنیم
در این آموزش، من به شما نشان خواهم داد که چگونه استفاده از شاخص ها برای رندر آرایه ای از کامپوننت ها در React می تواند مشکل ساز باشد. من همچنین به شما یاد خواهم داد که چگونه مشکلات رندر آرایه را با شناسه های منحصر به فرد کاهش دهید.
مثل همیشه، ما روی یک مثال دنیای واقعی کار خواهیم کرد و مشکلی را که در حین ساخت بازی 2048 خود در React با آن برخورد کردم، حل خواهیم کرد. تمام قطعات کد از این پروژه الهام گرفته شده است. اگر میخواهید قبل از خواندن این مقاله کد را مرور کنید، میتوانید آن را در GitHub پیدا کنید .
بازی 2048
اجازه دهید ابتدا قوانین بازی 2048 را توضیح دهم. بازیکن باید کاشیهایی را که اعداد یکسانی دارند ترکیب کند تا به عدد 2048 برسد. کاشیها فقط میتوانند شامل اعدادی باشند که قدرت دو را نشان میدهند که از 2 شروع میشود - یعنی 2، 4، 8، 16، 32 و غیره. آنها به عدد 2048 می رسند. تخته دارای ابعاد 4 در 4 کاشی است که می تواند تا 16 کاشی را در خود جای دهد.
در اینجا یک مثال است:
در این مقاله، من فقط نحوه رندر کردن آرایه ها در React را به شما آموزش می دهم و بهترین روش ها را در مورد رندر کردن فهرست ها در اجزای React به شما نشان می دهم.
متأسفانه، ما نمیتوانیم کل بازی را بسازیم زیرا این مقاله را گیجکننده میکند. اما اگر میخواهید این کار را از ابتدا انجام دهید، باید در دوره من در Udemy ثبت نام کنید، جایی که من شما را در ساخت بازی 2048 با انیمیشنها در React 18 راهنمایی خواهم کرد.
پیش نیازها
قبل از شروع، مطمئن شوید که برخی از اصول React را می دانید. هیچ چیز پیچیده ای نیست - فقط مطمئن شوید که قبلاً با React کار کرده اید، در غیر این صورت ممکن است کمی احساس گمراهی کنید.
اگر هنوز React را نمیشناسید، freeCodeCamp یک دوره 5 ساعته React برای مبتدیان دارد، پس قبل از خواندن این مقاله آن را تماشا کنید. شما همچنین می توانید در دوره React 18 من ثبت نام کنید.
حالا بیایید شروع کنیم.
چگونه عناصر آرایه را رندر کنیم
همانطور که در ابتدا اشاره کردم، صفحه بازی دارای ابعاد 4 در 4 کاشی است. این بدان معناست که بهترین ساختار داده برای ذخیره کاشی ها روی برد یک آرایه چند بعدی خواهد بود، مانند آنچه در زیر می بینید:
const board = [ [0, 0, 0, 0], [2, 0, 0, 0], [2, 0, 0, 0], [0, 0, 0, 0], ]
متأسفانه، این ساختار داده گران خواهد بود، زیرا نیاز به حلقه های تو در تو دارد که روی یکدیگر تکرار شوند. به همین دلیل تصمیم گرفتم این آرایه را به یک آرایه یک بعدی مسطح کنم:
const tilesOnBoard = [0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0]
همانطور که می بینید، عناصر خالی زیادی در این آرایه وجود دارد و فضایی را برای بهبود بیشتر فراهم می کند. ما می توانیم با جایگزین کردن مقادیر کاشی با اشیاء حاوی اطلاعات کاشی، مقدار عملیات را کاهش دهیم.
برای مثال، میتوانید نوع جدیدی را برای ذخیره متا دادههای هر کاشی مانند این معرفی کنید:
type TileModel = { position: [number, number]; value: number; };
همانطور که می بینید، این نوع داده کاشی ها را هوشمند می کند. هر کاشی جایگاه و ارزش خود را خواهد دانست. تصمیم گرفتم موقعیت را به صورت آرایه ای از دو عنصر ذخیره کنم. این عناصر مختصات x
و y
را نشان خواهند داد. به جای پیکسل، از شاخص های آرایه در آرایه بردی که در مرحله اول به آن اشاره کردم استفاده خواهم کرد.
حالا بیایید آرایه tilesOnBoard
را بهبود بخشیم و کاری کنیم که فقط کاشی های موجود را بدون مقادیر خالی ذخیره کند:
const tilesOnBoard = [ { position: [1, 0], value: 2 }, { position: [2, 0], value: 2 }, ]
به لطف این سادهسازی، میتوانم کاشیها را با استفاده از تابع map
ساده ارائه کنم که در تمام عناصر آرایه تکرار میشود و اجزای کاشی را از آنها ایجاد میکند.
const renderTiles = () => { return tilesOnBoard.map((tile: TileModel, index: number) => ( <Tile key={index} {...tile} /> )); };
بیایید برای لحظه ای روی آرگومان دوم تابع map
تمرکز کنیم. همانطور که می بینید، از فهرست آیتم آرایه tilesOnBoard
استفاده می کند. من از آن به عنوان یک ویژگی key
برای مقداردهی اولیه مولفه های React استفاده می کنم - در این مورد مولفه های Tile
.
اگر هرگز از ابزارهای key
استفاده نکردهاید، React به کلیدهایی نیاز دارد تا تشخیص دهد کدام عناصر تغییر، اضافه یا حذف شدهاند. کلیدها باید به هر آیتم داخل آرایه کامپوننت ها اختصاص داده شوند.
به همین دلیل است که من به همه کاشی ها شاخص های آرایه اختصاص دادم. متأسفانه، همانطور که در زیر می بینید، شاخص های آرایه بهترین شناسه های منحصر به فرد نیستند:
ممکن است تشخیص آنچه در اینجا اتفاق می افتد دشوار باشد، پس اجازه دهید به طور خلاصه توضیح دهم. اساسا، React از عناصر HTML موجود برای رندر کردن کاشیهای جدید استفاده مجدد میکند. این یک رفتار مورد نظر نیست - در عوض، باید کاشی های ادغام شده را حذف می کردم و بعد از هر حرکت یک کاشی جدید ایجاد می کردم.
اما چرا این اتفاق می افتد؟ پس از ادغام کاشی ها، یک کاشی جدید ایجاد می شود، و این بدان معناست که آرایه هنوز دارای دو عنصر با شاخص های آرایه یکسان است.
React از مکانیزمی به نام Virtual DOM برای شناسایی تغییرات و اصلاح عناصر در درخت DOM استفاده می کند. متأسفانه، این مکانیسم برای سرعت بهینه شده است به طوری که کل مؤلفه را تجزیه و تحلیل نمی کند، بلکه فقط پایه key
را تجزیه و تحلیل می کند. این بدان معنی است که React نمی تواند ایجاد کاشی جدید را از تغییر سبک در عنصر div موجود متمایز کند. به همین دلیل است که ما این موضوع را تجربه می کنیم.
برای تأیید درست بودن استدلال من، اجازه دهید نگاهی کوتاه به برگه Element در Chrome DevTools بیندازیم:
همانطور که می بینید، دو عنصر div موجود فقط ویژگی های سبک خود را تغییر دادند اما چیزی اضافه یا حذف نشد. این یک رفتار مورد نظر نیست، اما به ما می گوید که شاخص های آرایه، شناسه های منحصر به فرد ضعیفی برای اجزای React هستند.
اگر با ابزارهای توسعهدهنده کروم آشنا نیستید، باید مقاله من در مورد پیادهسازی رویدادهای لمسی موبایل در React 18 را بخوانید، جایی که من در مورد نحوه استفاده از آن تحقیق میکنم.
شناسه های منحصر به فرد به عنوان لوازم کلیدی
برای رفع مشکلات رندر آرایه در React، باید از برخی از شناسههای منحصربهفرد مانند شناسههای افزایشی، uuid یا موارد دیگر استفاده کنیم. برای تمرکز روی موارد ضروری، تصمیم گرفتم از کتابخانه ای به نام uid
استفاده کنم که می توانید با اجرای موارد زیر در ترمینال خود آن را نصب کنید:
npm install --save uid
اکنون باید کاشیها را برای پشتیبانی از آن شناسهها تغییر دهم. ابتدا یک id
ویژگی جدید در نوع داده متا tile اضافه کردم:
type TileModel = { id: string; position: [number, number]; value: number; };
و من به هر عنصر در آرایه tilesOnBoard
یک شناسه اختصاص دادم (در اینجا جایی است که کتابخانه uid
وارد عمل می شود):
const tilesOnBoard = [ { id: uid(), position: [1, 0], value: 2 }, { id: uid(), position: [2, 0], value: 2 }, ]
آخرین کاری که انجام دادم این بود که کمک کننده renderTiles
تغییر دادم:
const renderTiles = () => { return tilesOnBoard.map((tile: TileModel) => ( <Tile key={tile.id} {...tile} /> )); };
همانطور که می بینید، من یک آرگومان شاخص را از تابع map
حذف کردم و پایه key
را با یک شناسه منحصربفرد جایگزین کردم که به داده های متا کاشی اضافه کردم.
اکنون بازی 2048 مانند یک جذابیت عمل می کند:
نتیجه
در این مقاله متوجه شدید که شاخص ها بهترین گزینه برای رندر آرایه های کامپوننت در React نیستند و ممکن است منجر به رفتارهای عجیب و غریب شوند. اگر فقط یک نکته را باید از این مقاله به خاطر بسپارید، این است که همیشه باید از شناسه های منحصر به فرد به عنوان پایه key
اجزای React استفاده کنید.
آیا می خواهید ترفندهای بیشتری مانند این یاد بگیرید؟ شما باید به دوره React 18 من در Udemy بپیوندید. من به شما یاد می دهم که چگونه بازی 2048 را در React از ابتدا بسازید و راه حل هایی را برای رایج ترین اشتباهات توسعه دهندگان React به شما نشان می دهم.
ارسال نظر