۰
React محبوبترین فریمورک JavaScript در دنیا است، اما دلیل محبوبیتش فقط زیاد بودن استفادهکنندهها نیست؛ بلکه به این خاطر است که واقعاً عالی است. اکثر آموزشهای React سریع میروند سراغ نمایش چگونگی استفاده و مثالها و از بخش «چرا» میگذرند. این رویکرد مشکلی ندارد؛ اگر فقط میخواهید سریع شروع کنید و بازی کنید، مستندات رسمی React منابع زیادی برای شروع دارد.
اما این مطلب برای کسانی است که میپرسند: «چرا React؟ چطور React اینطوری کار میکند؟ هدف طراحی APIها چه بوده؟»
زندگی سادهتر است وقتی کامپوننتهای UI از شبکه، منطق تجاری (business logic) یا وضعیت اپلیکیشن (app state) بیخبر باشند. با دادن همان props، همیشه همان داده را رندر کن.
وقتی React معرفی شد، اساساً مفهوم کار فریمورکهای JavaScript را تغییر داد. در حالی که دیگران بر مدلهایی مثل MVC یا MVVM تاکید داشتند، React رویکرد کاملاً جدیدی اتخاذ کرد و رندر کردن نمای (view) را از مدل جدا کرد و معماری Flux را به اکو سیستم فرانتاند JS معرفی کرد.
دلیل این کار چه بود؟ چرا بهتر از فریمورکهای MVC قدیمی و کدهای به هم ریخته jQuery بود؟
در سال ۲۰۱۳، فیسبوک تازه به سختی توانسته بود ویژگی چت را یکپارچه کند؛ ویژگیای که باید در سرتاسر اپلیکیشن در صفحات مختلف در دسترس بود. این خودش یک اپلیکیشن پیچیده در دل اپلیکیشن پیچیدهتر بود. تغییرات بیقابوول (uncontrolled mutation) روی DOM و رفتار ناهمزمان چند کاربره ورود و خروج داده (multi-user I/O) مشکلات دشواری برای تیم فیسبوک ایجاد کرده بود.
مثلاً، چطور میشود پیشبینی کرد چه چیزی روی صفحه رندر میشود وقتی که هر بخش از برنامه در هر زمان میتواند DOM را تغییر دهد؟ و چطور میتوان تضمین کرد چیزی که رندر شده درست است؟
قبل از React هیچ کدام از فریمورکهای رایج چنین تضمینی نمیدادند. مشکلات race condition روی DOM از رایجترین باگها در برنامههای وب اولیه بودند.
“Non-determinism = parallel processing + mutable state” — مارتین اودرسکی (نویسنده زبان اسکالا)
کار اصلی تیم React رفع این مشکل بود. این کار را با دو نوآوری کلیدی انجام دادند:
«سادهترین راهی که ما پیدا کردهایم تا نماهایمان را بسازیم و رندر کنیم، این است که کاملاً از تغییر مستقیم پرهیز کنیم.» — تام اوچینو، کنفرانس JSConfUS ۲۰۱۳
Flux این مشکل تغییرات بیقابوول را مهار کرد. به جای اینکه به تعداد نامحدودی آبجکت (مدل) گوشفرمان بدهیم تا DOM را تغییر دهند، React یک راه واحد برای تغییر وضعیت کامپوننت معرفی کرد: ارسال (dispatch) به فروشگاه داده (store). وقتی وضعیت فروشگاه تغییر میکند، فروشگاه از کامپوننت میخواهد دوباره رندر شود.
وقتی میپرسند «چرا باید به React اهمیت بدهیم؟» جواب من ساده است: چون ما میخواهیم رندرهای نمای قطعی (deterministic view renders) داشته باشیم، و React این کار را خیلی آسانتر میکند.
توجه: خواندن دادهها از DOM برای اجرای منطق دامنه (domain logic) الگوی اشتباهی است و خلاف هدف React است. به جای آن، دادهها را از فروشگاه بخوان و تصمیمگیریها را قبل از زمان رندر انجام بده.
اگر فقط همین قابلیت رندر قطعی را داشت، باز هم نوآوری تحسینبرانگیزی بود. اما تیم React دست از نوآوری نکشید و ویژگیهای هیجانانگیز بیشتری ارائه دادند.
JSX توسعهای از JavaScript است که به شما اجازه میدهد به صورت دکلارتیو کامپوننتهای UI بسازید. مزایای مهم JSX عبارتند از:
قبل از JSX، اگر میخواستید UI دکلارتیو بنویسید، مجبور بودید از قالبهای HTML استفاده کنید که استاندارد مشخص و یکسانی نداشتند و هر فریمورک syntax مخصوص به خود داشت. مثلاً Angular با دستور *ngFor شناخته میشد.
JSX به عنوان یک superset از جاوااسکریپت همه امکانات زبان JS از جمله map، عملگرهای منطقی، expressions سهتایی (ternary)، فراخوانی توابع خالص (pure functions)، و الگوهای رشته (template literals) را به شما میدهد. این مزیت بزرگی نسبت به سایر فریمورکهاست.
دو نکته ممکن است اختلال ایجاد کنند:
class
از className
استفاده کنید.React رو راهحلی برای CSS بهصورت گذرا ارائه نکرده است. شما میتوانید یک آبجکت سبک (JavaScript style object) به ویژگی style پاس بدهید، که نام سبکها باید camelCase باشد، اما راههای دیگری هم وجود دارد:
React به جای eventهای DOM، یک wrapper به نام synthetic events ارائه میدهد. مزایا:
نکته: پیش از React نسخه ۱۷ نمیشد به خصیصههای event در async دسترسی داشت به خاطر event pooling که در نسخه ۱۷ حذف شده است.
چرخه عمر کامپوننتها برای محافظت از وضعیت کامپوننت وجود دارد. وضعیت نباید در حین رسم کامپوننت تغییر کند. بلکه کامپوننت باید به وضعیت مشخصی برسد، رندر شود، سپس چرخه عمر برای effects، بهروزرسانیها و رویدادها باز شود.
کتابخانه از نسخه ۰.۱۴ شروع به پشتیبانی از کلاسه برای lifecycle کرد. چرخه عمر به سه مرحله تقسیم میشود: Mounting، Updating و Unmounting.
داخل فاز بهروزرسانی، سه مرحله وجود دارد:
getSnapshotBeforeUpdate
از DOM بخوانید. کاربرد نمونهاش برای گرفتن موقعیت اسکرول یا اندازه یک المنت پیش از بازنویسی DOM است.componentDidUpdate
یا hook به نام useEffect
اثر خود را اجرا کنید.دن آبراموف یک دیاگرام جامع از lifecycle ارائه کرده که بسیار مفید است:
من فکر میکنم مدل ذهنی «کامپوننت به عنوان آبجکت طولانیمدت» خیلی ایدهآل نیست چون وضعیت کامپوننت در React قرار نیست به صورت مستقیم تغییر کند؛ بلکه باید جایگزین شود و هر جایگزینی منجر به رندر مجدد شود.
مدل فکری بهتر: هر بار که React رندر میکند، یک تابع قطعی که JSX برمیگرداند، اجرا میشود. این تابع خودش نباید عوارض جانبی (side-effects) داشته باشد؛ بلکه باید آنها را برای اجرای React صفبندی کند.
در React 16.8، مفهوم React hooks معرفی شد. hooks توابعی هستند که به شما اجازه میدهند با چرخه عمر کامپوننت بدون کلاس کار کنید.
یک hook معمولاً عوارض جانبی ایجاد میکند؛ یعنی اثرات قابل مشاهده بیرون از تابع و غیر از خروجی تابع.
مثلاً useEffect
به شما اجازه میدهد در زمان مناسب (مثل componentDidMount
، componentDidUpdate
، و componentWillUnmount
) اثرات خود را اجرا کنید.
یکی از مزایای hooks این است که میتوانید همه منطق مربوط به mount، update و unmount را در یک تابع نگه دارید بدون پراکندگی در چند متد.
hooks مزایای زیادی دارند:
در کل، بهتر است توابع و hooks را به کلاسها ترجیح بدهید چون کد کمتر، منظمتر، قابل فهمتر، تست پذیرتر و قابل استفاده مجدد بیشتری خواهید داشت.
برای ماژولولاریته و قابلیت استفاده مجدد بهتر، اجزای خود را به دو دسته تقسیم میکنم:
نکته: کامپوننتهای خالص با
React.PureComponent
متفاوتند.React.PureComponent
فقط محافظت از رندرهای اضافی است، ولی یک کامپوننت Pure بر پایه رفتار تابعی است.
کامپوننتهای Presentation:
Date.now()
)HOC یک کامپوننت است که یک کامپوننت دیگر میگیرد و یک کامپوننت جدید برمیگرداند که قابلیتهای بیشتری دارد.
این به شما اجازه میدهد به شکل تابعی کامپوننتها را پیچیدهتر کنید بدون اینکه کامپوننت اصلی از این اضافهها آگاه باشد یا وابسته شود.
برخلاف hooks یا render props، HOC بسیار قابل ترکیب است و میتوانید رفتار مشترک را با چند خط کد به راحتی روی همه کامپوننتها اعمال کنید.
نمونهای کاربردی از HOC در دنیای واقعی:
1import LessonPage from '../features/lesson-pages/lesson-page.js'; 2import pageHOC from '../hocs/page-hoc.js'; 3export default pageHOC(LessonPage);
بدون HOC باید هر بار ترکیبها را دستی و در جاهای مختلف تکرار کنید که دردسر و پیچیدگی زیادی ایجاد میکند.
برای درک بهتر React، مفاهیمی مثل توابع خالص، عدم تغییرپذیری (immutability)، curry کردن، اعمال جزئی (partial application) و ترکیب توابع را بهتر بشناسید. اینها را میتوانید با ویدئو و تمرینهای کدنویسی در EricElliottJS.com ببینید.
معمولاً React را با Redux، Redux-Saga و RITEway جفت کنید. برای سادهتر کردن کدهای Redux، Autodux و Immer را توصیه میکنند. برای transitionهای پیچیده، Redux-DSM مفید است.
وقتی پایهها را گذاشتید، Next.js و Vercel در راهاندازی، CI/CD و استقرار سرورلس کمک شایان توجهی است؛ انگار تیم DevOps تماموقت دارید اما هزینه کمتر.
امیدوارم این معرفی جامع به شما کمک کرده باشد بفهمید چرا React چنین جایگاه ویژهای در دنیای توسعه UI دارد و چطور توانسته چالشهای گذشته را حل کند و توسعه را سادهتر و لذتبخشتر نماید! موفق باشید.
۰
کد با می متعهد است که بالاترین سطح کیفی آموزش را در اختیار شما بگذارد. هدف به اشتراک گذاشتن دانش فناوری اطلاعات و توسعه نرم افزار در بالاترین سطح ممکن برای درستیابی به جامعه ای توانمند و قدرتمند است. ما باور داریم هر کسی میتواند با استمرار در یادگیری برنامه نویسی چالش های خود و جهان پیرامون خود را بر طرف کند و به موفقیت های چشم گیر برسد. با ما در این مسیر همراه باشید. کد با می اجتماع حرفه ای برنامه نویسان ایرانی.