ری اکت یکی از محبوب‌ترین فناوری‌ها محسوب می‌شود و در این نوشته قصد داریم به معرفی این فریمورک محبوب جاوا اسکریپت بپردازیم. برای مطالعه این راهنما باید اطلاعات اولیه‌ای از HTML و جاوا اسکریپت داشته باشید.

ری اکت چیست؟

ری اکت یکی از کتابخانه‌های جاوا اسکریپت است که در سال 2013 توسط تیم توسعه فیسبوک ساخته شده است. ری اکت قصد داشت رابط کاربری را ماژولار (با قابل استفاده مجدد) بکند و نگه‌داری آن را آسان‌تر سازد. بر اساس اعلام وب‌سایت رسمی ری اکت از آن برای «ساخت اجزای کپسوله شده‌ای استفاده می‌شود که حالت خود را مدیریت می‌کنند. سپس این اجزا با هم ترکیب می‌شوند تا UI های پیچیده‌ای ساخته شوند.»

در جای جای این نوشته مثال‌هایی از فیسبوک زده‌ایم و دلیل این امر آن است که مهندسان فیسبوک نخستین کسانی هستند که ری اکت را ساخته‌اند.

آیا زمانی که فیسبوک به جای استفاده از لایک به سمت استفاده از واکنش‌ها (ری‌اکشن‌ها) حرکت کرد را به خاطر می‌آورید؟ در این زمان به جای این که تنها نوشته‌ها را لایک کنیم، می‌توانستیم با آیکون قلب، یا صورتک‌ها و یا همان لایک به نوشته‌ها واکنش نشان دهیم. اگر این واکنش‌ها قرار بود در HTML نوشته شوند به کار بسیار زیادی برای تغییر دادن همه آن لایک ها به صورت ری‌اکشن نیاز بود.

این همان جایی بود که ری اکت مورد استفاده قرار گرفت. در واقع به جای پیاده‌سازی «جداسازی دغدغه‌ها»، ما در ری اکت با معماری متفاوتی روبرو هستیم. این معماری، ماژولار بودن را بر مبنای ساختار کامپوننتی افزایش می‌دهد. امروزه ما CSS ها را نیز جدا نگه می‌داریم؛ اما شما می‌توانید هر جزیی را هر قدر می‌خواهید اختصاصی کنید.

ری اکت در برابر وانیلا جاوا اسکریپت

زمانی که از وانیلا جاوا اسکریپت صحبت می‌کنیم، به طور معمول منظورمان نوشتن کدهای جاوا اسکریپتی است که به کتابخانه‌های دیگر مانند جی کوئری، ری اکت، آنگولار یا Vue نیاز نداشته باشند. اگر می‌خواهید در مورد این موضوعات و معانی این فریمورک‌ها بیشتر بدانید توصیه می‌کنیم به این نوشته مراجعه کنید.

برای این که این راهنما تا حد امکان خلاصه باشد، در ابتدا یا انتهای برخی قطعه‌های کد از (…) استفاده کرده‌ایم. این بدان معنی است که بخشی از آن کد حذف شده است.

راه‌اندازی ری اکت

اگر می‌خواهید یک اپلیکیشن واقعی ری اکت بسازید باید از ابزاری مانند Webpack استفاده کنید. وب پک کد شما را بسته‌بندی می‌کند، زیرا ری اکت از برخی الگوها استفاده می‌کند که به طور پیش‌فرض در مرورگر کار نمی‌کنند. از این لحاظ استفاده از Create React App کاملاً مفید است چون اغلب پیکربندی‌ها از قبل انجام شده است.

در حال حاضر ما از React CDN استفاده می‌کنیم که تنها برای مقاصد توسعه کد مناسب است. همچنین از Babel CDN استفاده می‌کنیم و از این رو می‌توانیم از برخی ویژگی‌های غیراستاندارد جاوا اسکریپت استفاده کنیم. در ادامه در مورد آن‌ها بیشتر صحبت خواهیم کرد.

در یک پروژه کامل ری اکت، باید اجزای مختلف به فایل‌های مختلف تقسیم شوند. با توجه به این که در این راهنما قصد ما آموزش است همه کدهای جاوا اسکریپت را فعلاً در یک فایل قرار می‌دهیم.

کامپوننت ری اکت

در این راهنما یک ویجت استتوس فیسبوک می‌سازیم، چون فیسبوک ری اکت را ساخته است.

در نظر بگیرید که ویجت فیسبوک در چند جای مختلف ظاهر می‌شود. شما می‌توانید یک استتوس، یا پست، یا پست ویدئویی و یا یک تصویر را لایک کنید. حتی می‌توانید یک صفحه را لایک کنید. هر بار که فیسبوک قصد دارد کارکرد لایک را استفاده کند، سعی نمی‌کند که آن را از نو در همه این مکان‌های مختلف قرار دهد. بنابراین باید از کامپوننت‌ها استفاده کرد. همه قطعه‌های با قابلیت استفاده مجدد یک صفحه وب به صورت یک کامپوننت نوشته می‌شوند. این کامپوننت می‌تواند بارها و بارها مورد استفاده قرار گیرد. بدین ترتیب کافی است کد را تنها یک جا بنویسیم و هر زمان که خواستیم آن را به‌روزرسانی کنیم. در این مرحله یک استتوس فیسبوک را بررسی کرده و آن را به کامپوننت‌های مختلفش تجزیه می‌کنیم.

خود استتوس نیز یک کامپوننت است. در یک تایملاین فیسبوک، کامپوننت‌های زیادی وجود دارند. ما قطعاً می‌خواهیم که از کامپوننت استتوس در موارد مکرر استفاده کنیم.

درون یک کامپوننت، زیرکامپوننت‌هایی وجود دارند که به صورت کامپوننت‌هایی درون یک کامپوننت بزرگ‌تر قرار می‌گیرند. این زیرکامپوننت‌ها نیز قابلیت استفاده مجدد دارند. ما می‌توانیم کامپوننت دکمه لایک را داشته باشیم که فرزند کامپوننت PhotoStatus و همچنین فرزند کامپوننت LinkStatus باشد. ممکن است زیرکامپوننت‌های ما چیزی شبیه زیر باشند:

ما حتی می‌توانیم زیرکامپوننت‌هایی را درون زیرکامپوننت‌ها داشته باشیم. بنابراین گروهی متشکل از لایک، کامنت و اشتراک می‌توانند کامپوننت ActionBar را داشته باشند. ممکن است کامپوننت‌هایی برای لایک کردن، کامنت گذاشتن و اشتراک درون آن وجود داشته باشند.

روش‌های مختلفی برای تجزیه این کامپوننت‌ها و زیرکامپوننت‌ها وجود دارد که به این بستگی دارد که از این کارکردها در اپلیکیشن خود استفاده مجدد می‌کنید یا نه.

شروع به کار با ری اکت

این راهنما را بر اساس سنت کلاسیک آموزش زبان‌های برنامه‌نویسی با مثالی از «Hello World» آغاز می‌کنیم و سپس به سمت نمونه‌هایی از استتوس های پیچیده‌تر حرکت می‌کنیم.

در فایل HTML ما عنصری به صورت یک div وجود دارد که یک id دارد. در این مورد نیز بر حسب عرف می‌بینیم که این div دارای id به صورت root است چون این عنصر در واقع ریشه اپلیکیشن ری اکت ما است.

این بخش از کد را باید درون تگ text/jsx قرار دهید بنابراین به صورت زیر درمی‌آید:

اینک کد ری اکت خود را می‌نویسیم:

اتفاقی که در کد فوق می‌افتد این است که پیام «Hello World» به صورت یک هدینگ H1 در صفحه نمایش می‌یابد. در ادامه همه این موارد را توضیح می‌دهیم.

ابتدا از یک کلاس ES6 استفاده کرده‌ایم که از کلاس React.Component به ارث می‌رسد. این همان الگویی است که در اغلب کامپوننت‌های ری اکت خود مورد استفاده قرار می‌دهیم.

سپس یک متد در کلاس خود داریم که یک متد خاص است که render نام دارد. ری اکت به دنبال متد render می‌گردد تا بداند چه چیزی را باید در صفحه رندر کند. این نام معنی زیای دارد. هر آنچه که از متد render بازگردد توسط آن کامپوننت رندر می‌شود.

در این مورد ما یک H1 با متن «Hello World» باز می‌گردانیم که دقیقاً آن چیزی است که باید در یک فایل HTML به طور نرمال باشد. در نهایت داریم:

ما از کارکرد ReactDOM برای اتصال کامپوننت ری اکت به DOM استفاده می‌کنیم.

ری اکت از چیزی استفاده می‌کند که DOM مجازی نام دارد و یک بازنمایی مجازی از DOM است که به طور معمول در وانیلا جاوا اسکریپت یا جی کوئری با آن سروکار دارید. روال reactDOM.render این DOM مجازی را به صورت DOM واقعی رندر می‌کند. در پشت صحنه ری اکت کار زیادی انجام می‌دهد تا زمانی که چیزی در رابط نیاز به تغییر دارد، DOM را به طور کارآمدی ویرایش کرده و مجدداً رندر بگیرد.

کامپوننت ما <HelloWorld /> شبیه یک تگ HTML به نظر می‌رسد. این ساختار بخشی از JSX است که یک افزونه برای جاوا اسکریپت است. شما نمی‌توانید از این افزونه به طور بومی (native) در مرورگر استفاده کنید. بلکه باید باز Babel استفاده کنید تا کد JSX را به جاوا اسکریپت معمولی ترجمه کند و بدین ترتیب مرورگر بتواند آن را درک کند. درواقع استفاده از JSX در ری اکت اختیاری است؛ اما در عمل در بسیاری از پروژه‌ها از آن استفاده می‌شود.

همچنین از عنصر داخلی جاوا اسکریپت document.getElementById برای دریافت عنصر root که در HTML ایجاد کرده‌ایم، بهره می‌گیریم. در نهایت در این عبارت ReactDOM.render، ما کامپوننت HelloWorld خودمان را به div الصاق می‌کنیم که در فایل HTML وجود دارد.

کدنویسی اولیه با ری اکت

اینک که توانستیم یک مثال Hello World بنویسیم، می‌توانیم شروع به نوشتن کامپوننت فیسبوک خود بکنیم. ابتدا کمی دموی زیر را بررسی می‌کنیم. ما در سراسر این راهنما از این دمو استفاده خواهیم کرد. می‌توانید همین الان به بررسی کد بپردازید؛ اما اگر از چیز زیادی سر در نیاوردید نباید نگران شوید. دلیل وجود بقیه این راهنما، توضیح همین نکات است. ابتدا با «هارد کد» کردن HTML برای ویجت آغاز می‌کنیم.

نکته: منظور از هارد کد یا کد سخت این است که بخشی از یک برنامه به طرز تغییرناپذیری کدنویسی می‌شود به طوری که دیگر امکان تغییر در آن بخش وجود نخواهد داشت.

با افزودن کمی CSS کد فوق به صورت زیر درمی‌آید:

در این لینک می‌توانید کد کامل را در Codepen مشاهده کنید. ما چهار کامپوننت ایجاد کرده‌ایم. یک کامپوننت Status که کامپوننت والد خواهد بود، یک کامپوننت Like که منطق لایک کردن را شامل می‌شود و کامپوننت Comment حاوی منطقی برای نوشتن نظر خواهد بود. در نهایت کامپوننت Like یک فرزند LikeIcon نیز دارد که زمانی که دکمه لایک را فشار می‌دهید، به تناوب نمایش یافته یا مخفی می‌شود.

معماری کامپوننت‌های ری اکت

پیش‌تر می‌رویم و کد HTML ی که برای این کامپوننت‌ها نوشته‌ایم را تجزیه می‌کنیم. کار خود را با پوسته یک کامپوننت آغاز می‌کنیم و آن را رندر می‌کنیم تا مطمئن شویم که کار می‌کند یا نه.

یک نکته جالب در مورد کد فوق این است که باید خصوصیت «class» را به «className» تغییر دهیم. کلاس به معنی چیزی است که در جاوا اسکریپت وجود دارد و به کلاس‌های ES6 اشاره می‌کند. برخی خصوصیات در JSX متفاوت از آن چه در HTML هستند نام‌گذاری می‌شوند. همچنین می‌توانیم HTML خود را حذف کنیم و تنها عناصری که ID روت دارند را نگه‌داریم. این عنصر div والد صرفاً برای سبک‌بندی استفاده می‌شود.

در این کد بخش HTML را می‌بینیم که در کامپوننت استتوس استفاده می‌شود. توجه کنید که برخی از HTML های اولیه دیگر وجود ندارند، چون به زیرکامپوننت‌ها انتقال یافته‌اند. اینک دومین کامپوننت را ایجاد می‌کنیم و سپس آن را در کامپوننت استتوس خود می‌گنجانیم.

این هم کد کامپوننت comment است. این کد یک بخش textarea برای واردکردن متن و یک کنترل text دارد که نشان می‌دهد چه مقدار از کاراکترهای ما باقی مانده است. توجه کنید که هر دو این کنترل‌ها درون یک div پیچیده شده‌اند. دلیل این امر آن است که ری اکت باید همه محتواهای یک کامپوننت را درون تگ‌های HTML بپیچد. اگر آن div والد را نداشته باشیم، یک textarea و یک تگ small بازگشت داده می‌شد.

بنابراین باید این کامپوننت را درون کامپوننت status قرار دهیم، چون این زیرکامپوننت آن است. این کار از طریق همان ساختار JSX که برای رندر کردن کامپوننت Status استفاده کردیم میسر است.

اینک کافی است همین کار را برای لایک نیز انجام دهیم:

سپس باید آن را درون کامپوننت Status اصلی بگنجانیم.

اینک ما موفق شده‌ایم کدهای HTML خود را ری اکت دار بکنیم؛ اما این کد هنوز هیچ کاری انجام نمی‌دهد، بنابراین در ادامه این وضعیت را نیز اصلاح می‌کنیم. در نهایت کدی که در این بخش نوشته‌ایم به این صورت در آمده است.

وضعیت‌ها و مشخصات

ما دو تعامل مختلف داریم که می‌خواهیم پیاده‌سازی کنیم:

  • ابتدا می‌خواهیم آیکون لایک تنها در صورتی نمایش یابد که فشرده شده باشد.
  • دوما می‌خواهیم تعداد کاراکترهایی که فرد می‌تواند در هر لحظه درج کند، نمایش یابد.

پس با ما همراه باشید تا در ادامه این مشخصات را پیاده‌سازی کنیم.

مشخصات (props)

تصور کنید که می‌خواهیم یک کادر نظرات داشته باشیم که امکان درج تعداد مختلفی از حروف را در بخش‌های متفاوت فراهم سازد. برای مثال، در یک استتوس می‌خواهیم کاربر بتواند یک متن 200 حرفی وارد کند. با این حال در یک تصویر می‌خواهیم کاربر تنها بتواند به اندازه 100 حرف پاسخ دهد.

ری اکت امکان ارسال مشخصاتی را از کامپوننت PictureStatus و Status می‌دهد که تعیین می‌کنند چه تعداد از حروف در این کامپوننت‌ها مجاز هستند. بدین ترتیب دیگر لازم نیست دو کامپوننت مختلف برای این دو کارکرد طراحی کنیم. ساختار مشخصات چیزی شبیه زیر است:

این مشخصات شبیه خصوصیات HTML به نظر می‌رسند. اگر یک رشته را از طریق این مشخصات ارسال کنید نیازی به براکت ندارید. هر نوع داده دیگر یا متغیری که در این مشخصات ارسال می‌شوند، باید درون براکت باشند. سپس درون این کامپوننت مشخصات خود را به صورت زیر تعریف می‌کنیم:

مشخصات درون خصوصیت props این وهله بسته‌بندی شده‌اند و از این رو می‌توانیم از طریق this.props.myPropName به آن‌ها دسترسی داشته باشیم. بنابراین در ادامه 140 کاراکتر که در بخش قبلی هارد کد شده بود را به عددی که از بیرون قابل تعویض است، تغییر می‌دهیم. ابتدا محلی که کامپوننت Comment درون کامپوننت Status مقداردهی می‌شود را عوض می‌کنیم (دقت کنید که بخشی از کد حذف شده است)

سپس محدودیت 140 کاراکتر هارد کد شده در کامپوننت Comment را تغییر می‌دهیم:

وضعیت (state)

مشخصاتی که از یک کامپوننت به کامپوننت دیگر ارسال می‌کنیم، هرگز درون کامپوننت فرزند تغییر نمی‌یابند. آن‌ها می‌توانند درون کامپوننت والد تغییر یابند؛ اما در اغلب موارد ما خصوصیاتی داریم که می‌خواهیم در طی عمر یک کامپوننت تغییر دهیم. برای نمونه می‌خواهیم حساب تعداد کاراکترهایی که کاربر در یک کادر متنی وارد کرده را داشته باشیم و یا بدانیم که آیا یک استتوس لایک شده یا نه. ما این خصوصیات را که می‌خواهیم تغییر دهیم درون کامپوننتی به نام state ذخیره می‌کنیم.

شاید متوجه شده باشید که ما در ری اکت با مقدار زیادی از تغییرناپذیری (immutability) مواجه هستیم. منظور از immutability این است که یک شیء پس از ایجاد نمی‌تواند تغییر یابد یا دامنه تغییرات آن محدود است. دلیل این وضعیت آن است که ری اکت تا حدود زیادی تحت تأثیر پارادایم کارکردی است و از این رو از عوارض جانبی آن مصون نیست.

ما می‌خواهیم این وضعیت (state) هر زمان که وهله جدیدی از کامپوننت ایجاد می‌شود، ساخته شود و از این رو از سازنده کلاس ES6 برای ایجاد آن استفاده می‌کنیم. اگر می‌خواهید اطلاعاتی در مورد کلاس‌های ES6 پیدا کنید می‌توانید از این آموزش بهره بگیرید. State یک شیء است که هر نوع جفت‌های کلید-مقدار که بخواهیم می‌توانیم در آن بگنجانیم. در این مورد می‌خواهیم یک characterCount داشته باشیم که با آن تعداد کاراکترهایی که کاربر تایپ کرده است را ذخیره کنیم. فعلاً آن را برابر با صفر قرار می‌دهیم:

اینک آن را از مشخصات maxLetters کسر می‌کنیم و بدین ترتیب می‌توانیم بدانیم که کاربر چند کاراکتر دیگر می‌تواند وارد کند:

اگر مقدار characterCount را افزایش دهید، کاراکترهای باقی مانده نیز افزایش می‌یابند. اما وقتی در این مرحله شروع به تایپ کنید می‌بینید که هیچ اتفاقی رخ نمی‌دهد. دلیل آن این است که ما هرگز مقدار characterCount را تغیر نداده‌ایم. ما می‌بایست یک کنترل رویداد (Event Handlers) به کادر متنی textarea اضافه کنیم که هر زمان کاربر شروع به تایپ می‌کند مقدار characterCount را تغییر دهد.

کنترل رویداد در ری اکت

اگر تاکنون کدهای جاوا اسکریپت نوشته باشید، احتمالاً از کنترل‌های رویداد برای تعامل با ورودی کاربر استفاده کرده‌اید. اینک نیز از همان رویه در ری اکت استفاده می‌کنیم؛ گرچه ساختار در این جا اندکی متفاوت است. در ادامه یک مدیر onChange به textarea اضافه می‌کنیم. درون آن یک ارجاع به متد کنترل رویداد قرار می‌دهیم که هر بار کاربر چیزی در textarea وارد کند، فعال می‌شود.

اینک باید یک متد handleChange ایجاد کنیم.

در این لحظه ما توانسته‌ایم مقدار event.target.value را در کنسول نمایش دهیم. روند کار همانند زمانی است که از ری اکت استفاده نمی‌کردیم؛ گرچه با نگاهی دقیق‌تر می‌فهمیم که شیء رویداد، اندکی متفاوت است. اگر به کنسول نگاه کنید می‌بینید که آنچه در کادر متنی وارد می‌کنیم را نمایش می‌دهد. اینک باید خصوصیت characterCount را به‌روزرسانی کنیم. در ری اکت هرگز state را مستقیماً تغییر نمی‌دهی، بنابراین نمی‌توانیم کدی مانند این بنویسیم: this.state.characterCount = event.target.value.length بلکه به جای آن باید از متد this.setState استفاده کنیم.

اما می‌بینید که این کد موجب خطا می‌شود: «Uncaught TypeError: this.setState is not a function» این کد به ما می‌گوید که باید محتوای کلاس ES6 را درون کنترل رویداد نگه‌داریم. این کار از طریق اتصال this به متد در سازنده ممکن است.

اینک تقریباً موفق شده‌ایم. تنها کافی است توانایی تغییر متناوب نمایش دکمه like را بنویسیم. باید یک سازنده به کامپوننت like خود اضافه کنیم. در این سازنده باید state کامپوننت را مقداردهی اولیه کنیم. این چیزی است که در طی چرخه عمر کامپوننت صرف نظر از این که استتوس لایک شود یا نه تغییر خواهد یافت.

اینک باید یک کنترل رویداد بنویسیم که وضعیت لایک شدن یا نشدن استتوس را تغییر دهد:

تفاوت این است که تابع فراخوانی this.setState یک پارامتر previousState—می‌گیرد. همان طور که احتمالاً از روی نام آن حدس می‌زنید، این پارامتر مقدار state را پیش از فراخوانی this.setState نگه‌داری می‌کند. setState ناهمگام است و از این رو می‌تواند به استفاده از this.state.liked درون آن وابستگی داشته باشد.

اینک باید موارد زیر را داشته باشیم:

الف) فراخوانی کنترل رویداد هر زمان که کاربر بر روی دکمه لایک کنید کند

ب) تنها زمانی که مقدار لایک true است، آیکون لایک نمایش یابد.

اینک همه کارکردهای ما به مرحله اجرا در آمده‌اند. اما در ادامه برخی کامپوننت‌های اضافی را نیز بررسی می‌کنیم.

کامپوننت‌های کارکردی

اگر فکر می‌کنید تا همین جا که مطالعه کردید برای شما کافی است، اصراری برای مطالعه این بخش وجود ندارد؛ اما در این بخش یک اصلاح سریع برای بازسازی کد این راهنما معرفی می‌کنیم. اگر کامپوننت‌هایی ایجاد کنیم که state نداشته باشند (این‌ها را کامپوننت‌های بی وضعیت می‌نامیم) می‌توانیم کامپوننت‌های خود را به جای کلاس‌های Es6 به صورت تابع درآوریم. در این حالت LikeIcon ما چیزی شبیه زیر خواهد بود:

ما به جای استفاده از متد Render تنها UI کامپوننت را باز می‌گردانیم. در این لینک می‌توانید کد مربوط به این بازسازی را ببینید.

سخن پایانی

در این نوشته ما در مورد معماری‌های کامپوننت‌ها صحبت کردیم که ساختار پایه‌ای ری اکت و JSX محسوب می‌شوند. همچنین در مورد state و props یعنی وضعیت‌ها و مشخصات صحبت کردیم. کنترل‌های رویداد و کامپوننت‌های کارکردی نیز معرفی شدند. کد کامل این راهنما را می‌توانید اینجا مشاهده کنید. اگر قصد دارید این کد را گسترش دهید پیشنهاد می‌کنیم که لایک را به صورت واکنش تغییر دهید و یا یک کامپوننت عکس ایجاد کنید که از برخی از کامپوننت‌هایی که در این راهنما ساخته‌ایم، مجدداً استفاده کند.

اگر این نوشته مورد توجه شما قرار گرفته است، پیشنهاد می‌کنیم موارد زیر را نیز بررسی کنید:

==

میثم لطفی (+)

«میثم لطفی» دانش‌آموخته ریاضیات و شیفته فناوری به خصوص در حوزه رایانه است. وی در حال حاضر علاوه بر پیگیری علاقه‌مندی‌هایش در رشته‌های برنامه‌نویسی، کپی‌رایتینگ و محتوای چندرسانه‌ای، در زمینه نگارش مقالاتی با محوریت نرم‌افزار نیز با مجله فرادرس همکاری دارد.

بر اساس رای 2 نفر

آیا این مطلب برای شما مفید بود؟

نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *