پاس دادن props به props.children با استفاده از React.cloneElement

ارتباط بین کامپوننت‌ها یکی از مهمترین و اولین گام در یادگیری ری‌اکت هست که تقریبا بعد از یه مدت کار کردن با این کتابخانه محبوب مثل دنده عوض کردن ماشین بدیهی و پیش پا افتاده میشه برامون. اما همیشه این ارتباط به این صورت سر راست و ساده نمیشه و ممکنه حالت های مختلفی از این ارتباط رو لازم داشته باشیم. در این مقاله سعی کردم در ابتدا حالت‌های مختلف ارتباط بین کامپوننت‌ها را مرور کنیم و ببینیم معمولا در چه مواردی میتونیم ازشون استفاده کنیم و در آخر به حالت مورد نظرمون یعنی با استفاده از React.cloneElement می‌پردازیم.روش اول – function as a childrenدر این روش فرزند به عنوان یک فانکشن به کامپوننت داده می شود و در نتیجه به عنوان آرگومان مقادیری همچون state کامپوننت والد را می توانیم به فرزند پاس بدیم. نمونه این مورد را احتمالا به هنگام استفاده از context آنجایی که consumer را فراخوانی می کنیم مشاهده کردیم و یا اگر با کتابخانه react transition group کار کرده باشید حتما با مثالی مشابه کدی که در زیر آوردم در داکیومنت این کتابخانه روبرو شدید:مثالی از function as childrenهمانطور که در تصویر میبینید ما به وسیله پارامتر state به state کامپوننت والد که یکی از موارد: ‘entering’ , ‘entered’ , ‘exiting’ , ‘exited’ میتواند باشد دسترسی داریم.روش دوم – render propبرای اینکه چندین jsx مورد نظر رو در چند قسمت مشخص از کامپوننت والد رندر کنیم میتونیم از این روش استفاده کنیم. همچنین مقادیری از کامپوننت والد هم میتونیم به این jsx پاس بدیم.به کد زیر توجه کنید. برای مثال یه کامپوننت Card درست کردم که هر چیزی به عنوان children داخل Collapse رندر می شود و به عنوان هدر یه Button گذاشتم که در واقع در طراحی هدر دستمون بازه و هر چیزی میتونیم به Card پاس بدیم.مثالی از render propالبته بهتره تا وقتی که دلیل خاصی ندارین، به جای پاس دادن فانکشن، یه کامپوننت پاس بدید. برای واضح‌تر شدن توضیحم به نمونه کد زیر دقت کنید.مثالی از Component as a propروش سوم – use React.cloneElementآخرین روشی که در این مقاله قصد داریم به آن بپردازیم، پاس دادن props به props.children با استفاده از React.cloneElement هست. معمولا کم پیش میاد ازش استفاده بشه اما روش باحالیه و کار رو برای استفاده از کامپوننت ها خیلی راحت می کنه. یادتون باشه که این با React.createElement فرق داره. createElement ، در واقع jsx توسط Babel کامپایل میشه به React.createElement. آبجکتی که ری اکت برای نمایش UI استفاده میکنه.اما cloneElement برای کلون کردن یه المنت و پاس دادن props جدید استفاده میشه.فرض کنید یه جایی از پروژه قصد داریم کامپوننت Tabs بسازیم که این کامپوننت قرار هست به تعداد مورد نیاز TabItem نمایش بده. خب چالش هایی که داریم این خواهد بود که چطور بفهمیم روی کدوم TabItem کلیک شده.هر آیتم باید ایندکسی داشته باشه تا به عنوان currentItem در state قرار بگیرهدر هر بار استفاده ممکنه آیتم ها استایل متفاوتی داشته باشند، پس هر آیتم نیاز به className داره.بعدا هم مورد دیگه ای به ذهنمون برسه باید به تک تک آیتم ها اضافه بشه.خب از اونجایی که ما نمیدونیم children قراره چی باشه و هربار این همه مورد رو به آیتم ها اضافه نکینم بهتره که با کامپوننت والد یعنی همون Tabs طرف حساب بشیم. بریم سراغ کد و ساختن کامپوننت TabItem :خب کامپوننت TabItem رو آماده کردیم که قراره به عنوان فرزند کامپوننت Tabs ازش استفاده کنیم. من برای ui از کتابخانه Material ui استفاده می کنم به همین خاطر استایل ها اینجا به صورت css-in-js هست و از makeStyles متریال استفاده شده. حالا میریم سراغ کامپوننت Tabs:مهمترین بخش این کامپوننت دریافت آرایه children و ساختن آرایه جدیدی از آن با props مد نظر است که به وسیله React.Children.map این کار رو انجام دادیم و هر آیتم توسط React.cloneElement کلون و آبجکتی با props مدنظر ایجاد میشه.من در این کامپوننت از state داخلی هم استفاده کردم که در صورت undefined بودن مقدار مقادیر state داخلی مورد استفاده قرار بگیره.حالا خیلی تمیز و خلاصه میتونیم از کامپوننتمون استفاده کنیم.همینطور که دیدید تمامی props مورد نیاز TabItem را به کامپوننت Tabs پاس دادیم که این خیلی کار ما رو در هر بار استفاده راحت می کنه و در عین حال خوانایی بهتری هم داره.TabItem with parent propsامیدوارم که این آموزش داخل پروژه هاتون به کار بیاد و تونسته باشه گره ای از مشکلاتتون رو باز کنه. شاید دوستانی هم داشته باشید که دنبال چنین راه حلی باشند، لطفا به اون ها هم معرفی کنید. سوالی هم اگه داشتین میتونین در کامنت بپرسین، سعی میکنم در زودترین زمان ممکن جواب بدم.