تا به اینجای آموزش ما توانستیم یک برنامه ساده را بدون استفاده از داده های خارجی ایجاد کنیم. حال می خواهیم با مطالبی که تاکنون آموختیم، پروژه ی جدیدی را شروع کنیم.
در قسمت های قبلی دیدیم که چطور می شود در بین لیستی از اشیاء پیمایش کرد و چندین کامپوننت را در صفحه رندر کنیم.
قبل از اینکه با افزودن داده های خارجی، پیچیدگی برنامه مان را زیاد کنیم، مروری خواهیم داشت بر چگونگی تکرار عناصر (کامپوننت) در یک برنامه.
به دلیل اینکه مرورگر، پسوند jsx را تنها به عنوان کدهای جاوا اسکریپت ساده می بیند، تنها می توانیم از دستورات جاوا اسکریپت در تگ قالب ({}) استفاده کنیم. کدهای زیر را ببینید:
const App = (props) => { return ( <ul> {a.map(i => { return <li>{i}</li> })} </ul> ) }
اگر به تگ قالب ({ }) نگاه کنید می بینید که تنها شامل دستورات جاوا اسکریپت است. ما می توانیم از هر نوع دستور جاوا اسکریپتی مثل تکرارکننده های (iterator) بومی مثل map و forEach در آن استفاده کنیم.
بیایید ببینیم منظورمان چیست؟ درمثال قبلی مقدار متغیر a که از نوع عددی (integer) بود به لیستی از اعداد تغییر می دهیم:
const a = [1, 10, 100, 1000, 10000];
حال می توانیم توسط متد map لیست فوق را پیمایش کرده و یک لیست جدیدی از کامپوننت های ری اکت که DOM مجازی (virtual DOM) را خواهند ساخت، ایجاد کنیم.
در صورتیکه با مفهوم DOM آشنایی ندارید، مقاله زیر بهترین منبع مورد نظر می باشد. حتما آن را مطالعه کنید:
const App = (props) => { return ( <ul> {a.map(i => { return <li>{i}</li> })} </ul> ) }
تابع map
یکی از توابع داخلی جاوا اسکریپت است که بر روی آرایه ها استفاده می شود. این تابع یک کالبک (یا تابع) را به عنوان پارامتر گرفته و آن را بر روی تمام عناصر آرایه اجرا می کند. در مثال فوق این تابع چهار بار اجرا می شود و در ابتدا مقدار i برابر 1 بوده و سپس با اجرای بعدی برابر 10 و تا به آخر، خواهد شد.
حال برنامه ای که در روز دوازدهم ایجاد کرده بودیم را با کامپوننت App که در اینجا ساختیم، بروزرسانی می کنیم.
ابتدا فایل src/App.js را باز کرده و محتوای کامپوننت App را با این سورس جایگزین می کنیم و متغیرهای اضافی را هم حذف می کنیم. کدهای src/App.js باید مطابق زیر باشد:
import React from 'react'; const a = [1, 10, 100, 1000, 10000]; const App = (props) => { return ( <ul> {a.map(i => { return <li>{i}</li> })} </ul> ) } export default App
ترمینال را باز کرده و با دستور npm start برنامه را اجرا کنید.
اگر developer console مرورگر را باز کنید، می بینید که یک پیام خطا در آن نمایش داده می شود. این خطا به این خاطر است که ری اکت نمی تواند کامپوننت های منحصر به فرد در لیست را تشخیص دهد. برای افزایش کارایی، ری اکت با استفاده از DOM مجازی سعی می کند تا تعداد عناصر DOM که در هنگام نمایش ویوها نیاز است را محدود کند. اگر تغییری اتفاق نیفتد، ری اکت هیچ بروزرسانی در مرورگر انجام نمی دهد.
این کار یک ویژگی خوب برای ساخت برنامه های تحت وب است، اما گاهی اوقات باید یک id منحصر به فرد برای عناصرمان اضافه کنیم. پیمایش در یک لیست و نمایش کامپوننت ها در متد map یکی از آن مواقعی است که باید از این قابلیت استفاده کنیم.
ری اکت یک پروپرتی ویژه به نام key دارد که به هر کدام از عناصر یک لیست اختصاص می یابد.
مقدار پروپرتی key هر چیزی می تواند باشد، اما باید برای آن عنصر منحصر به فرد باشد. در این مثال می توانیم از مقدار متغیر i به عنوان یک کلید منحصر به فرد استفاده کنیم، چون این آرایه هیچ مقدار تکراری ندارد. حال کد بالا را مطابق زیر بروزرسانی می کنیم:
const App = (props) => { return ( <ul> {a.map(i => { return <li key={i}>{i}</li> })} </ul> ) }
در آموزش های قبلی درباره ساخت رابطه والد-فرزند صحبت کردیم، اما حالا می خواهیم ببینیم که چطور می شود در داخل کامپوننت والد به کامپوننت فرزند دسترسی داشته باشیم و چطور آنها را رندر کنیم.
در درس یازدهم، یک کامپوننت <Formatter/> برای مدیریت فرمت بندی تاریخ در داخل کامپوننت clock ایجاد کردیم تا به کاربرانمان این امکان را بدهیم که ساعت را مطابق نیاز خود سفارش سازی کنند.
همان طور که در زیر می بینید، کدها کمی نامرتب و زشت به نظر می رسد:
const Formatter = (props) => { let children = props.format.split('').map((e, idx) => { if (e === 'h') { return <Hour key={idx} {...props} /> } else if (e === 'm') { return <Minute key={idx} {...props} /> } else if (e === 's') { return <Second key={idx} {...props} /> } else if (e === 'p') { return <Ampm key={idx} {...props} /> } else if (e === ' ') { return <span key={idx}> </span>; } else { return <Separator key={idx} {...props} /> } }); return <span>{children}</span>; }
حال می توانیم از آبجکت React.children برای پیمایش در میان لیستی از آبجکت های ری اکت استفاده کنیم. همان طور که می بینید، کدهای زیر ظاهر بهتری دارند.
const Formatter = ({format, state}) => { let children = format.split('').map(e => { if (e == 'h') { return <Hour /> } else if (e == 'm') { return <Minute /> } else if (e == 's') { return <Second /> } else if (e == 'p') { return <Ampm /> } else if (e == ' ') { return <span> </span>; } else { return <Separator /> } }); return (<span> {React.Children .map(children, c => React.cloneElement(c, state))} </span>) }
در درس های قبلی گفتیم که مرورگرها کدهای jsx را به جاوا اسکریپت تبدیل می کنند، مانند زیر:
React.createElement("div", null, React.createElement("img", {src: "profile.jpg", alt: "Profile photo"}), React.createElement("h1", null, "Welcome back Ari") );
بجای ساخت یک کامپوننت جدید، گاهی اوقات می خواهیم یک کپی از یک کامپوننت بگیریم و یا پروپرتی یا فرزندهایی را به آن اضافه و همان پروپرتی هایی که دارد را حفظ کنیم. برای این منظور از React.cloneElement
استفاده می کنیم.
React.cloneElement()
، api هایی مشابه با React.createElement
دارد و آرگومان های آن عبارتند از:
در مثال Formatter یک کپی از تمام فرزندان لیست ایجاد ( که شامل کامپوننت های <Home/> و <Minute/> و... می شد) و توسط props آنها را به آبجکت state ارسال کردیم.
آبجکت React.children
تعدادی تابع کاربردی برای کار با عنصرهای فرزند دارد. در مثال Formatter بالا، با استفاده از تابع map تمام عنصرهای فرزند را پیمایش کرده و یک کپی از آنها را در لیست می ریزیم. سپس برای هر کدام از آنها در صورت لزوم یک key تعیین می کنیم.
حال با استفاده از تابع ()
React.children.map
کامپوننت App را بروزرسانی می کنیم:
const App = (props) => { return ( <ul> {React.Children.map(a, i => <li>{i}</li>)} </ul> ) }
نتیجه اجرا در مرورگر:
React.children چند متد کاربردی دیگری هم دارد. ما در این آموزش از روش React.children.map بیشتر از بقیه استفاده کردیم، اما برای مشاهده متدهای دیگر به این آدرس مراجعه کنید.
تا به اینجای آموزش ما تنها با داده های محلی کار کردیم و روی داده های خارجی تمرکزی نداشتیم. در درس بعدی قصد داریم با یک سرور ارتباط برقرار کرده و از داده های آن سرور در برنامه مان استفاده کنیم.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.