هر جا که بحث از react باشد معمولا نام redux را هم خواهید شنید اما آیا با آن آشنایی دارید؟ برای درک redux باید ابتدا بدانید که application state (به معنی «وضعیت برنامه») به چه معناست. State همان محتویاتی است که به همبرگر ما اضافه می شد! State یک سوال درباره هویت کاربر (احراز هویت) است! State سوالی است که می گوید آیا modal ما باز است یا خیر! ویکی پدیا به زبان کلی می گوید:
در علوم رایانه و فناوری اطلاعات، به برنامهای که اتفاقات پیشین و تعاملهای کاربر را بهخاطر بسپارد، حالتمند (به انگلیسی: stateful) گفته میشود؛ این اطلاعات بهخاطرسپردهشده «حالت» یا «وضعیت» (به انگلیسی: state) نامیده میشوند.
این تعریف بسیار کلی است، اگر بخواهم دقیق تر توضیح بدهم می گویم: در هر لحظه در مموری برنامه شما اطلاعات خاصی ذخیره می شود که از طریق متغیرها، کلاس ها و ... در دسترس هستند. بنابراین به تمامی اطلاعات ذخیره شده در برنامه شما در یک لحظه خاص، وضعیت آن برنامه (application state) گفته می شود. به طور مثال اگر یک درخواست POST به سرور شما بیاید اطلاعات آن در مموری ذخیره می شود و شما بعدا می توانید با دستورات مناسب خود این اطلاعات را دریافت کنید. وضعیت یا state برنامه شما قبل و بعد از این درخواست POST کاملا متفاوت خواهد بود.
فرض کنید یکی از دوستان خود را در خیابان ببینید. به او می گوید «وضعیت چطوره؟ حالت خوبه؟» وضعیت دوست شما یعنی وضعیت تمام زندگی او در آن زمان خاص که بعدا تغییر خواهد کرد. وضعیت برنامه ها هم به همین شکل است، مثلا وضعیت برنامه به ما می گوید درون همبرگر خود چه چیزهایی داریم یا اینکه modal ما باز یا بسته است و الی آخر. به همین دلیل وقتی می گویند یک برنامه stateless (بدون وضعیت) است یعنی با هر بار refresh شدن صفحه، اطلاعات قبلی را به طور کامل فراموش می کند.
مدیریت state در برنامه های بزرگ می تواند کار طاقت فرسایی شود. React به ما خاصیت state را می دهد تا از آن استفاده کنیم اما اگر یادتان باشد در پروژه همبرگرساز خودمان با مشکلات زیادی روبرو بودیم و برای پاس دادن اطلاعات بین کامپوننت ها مجبور بودیم از query parameter ها استفاده کنیم (اطلاعات را از URL انتقال دادیم). به برنامه فرضی زیر توجه کنید:
اگر چنین برنامه ای داشته باشیم که دارای یک کامپوننت users (کاربران) و یک کامپوننت products (محصولات) باشد و کاربر بخواهد وارد داشبورد خود شود مشکلی نخواهیم داشت. باید با کامپوننت auth (احراز هویت) چک کنیم که کاربر وارد حساب کاربری خود شده باشد اما اگر بخواهیم به اطلاعات cart (سبد خرید) نیز دسترسی داشته باشیم چطور؟ همانطور که در تصویر بالا می بینید باید ابتدا اطلاعات را به products و سپس به App و سپس به Users و سپس به Auth یا Dashboard ارسال کنیم. این مسیر بسیار پیچیده واقعا غیرضروری است و مدیریت state برنامه های ما نباید اینقدر پیچیده باشد. اگر در react از جاوا اسکریپت استفاده می کنیم چرا نمی توانیم یک متغیر سراسری داشته باشیم که state برنامه درون آن قرار بگیرد و ما بتوانیم از هر جای برنامه به آن دسترسی داشته باشیم؟ Redux کاری شبیه به همین موضوع را انجام می دهد!
اول از همه چیز باید تاکید کنم که Redux یک کتابخانه کاملا مستقل از React است و در برنامه های دیگر نیز مورد استفاده قرار می گیرد اما به دلیل شهرت آن به همراه React معمولا با هم شناخته می شوند. حالا سعی کنید به تصویر زیر توجه کنید:
این تصویر جریان کاری Redux را به شما نشان می دهد که در جهت عقربه های ساعت حرکت می کند و از central store یا نقطه مرکزی redux شروع می شود. دوست دارم همانطور که توضیحات من را می خوانید حواستان به این تصویر نیز باشد و با من مرحله به مرحله جلو بروید.
در Redux یک محل ذخیره مرکزی وجود دارد که تمام state برنامه را در خود ذخیره می کند بنابراین یک نقطه مرکزی را درون برنامه خود تصور کنید (مثلا یک شیء بزرگ و سراسری جاوا اسکریپت) که در کنار آن کامپوننت ها وجود دارند. این کامپوننت ها نیاز به اطلاعات state دارند و می خواهند آن را تغییر دهند اما آن را مستقیما تغییر نمی دهند. چرا؟ به دو دلیل! اولا سیستم واکنش پذیری react تغییرات سراسری اینچنینی را تشخیص نمی دهد و دوما اگر هر کامپوننتی از هر جایی state را مستقیما تغییر دهد دیگر نمی توانیم تشخیص دهیم که یک خطای فرضی از کدام کامپوننت آمده است و در چه قسمتی از برنامه به دنبال خطا بگردیم.
بنابراین Redux واقعا یک شیء جاوا اسکریپتی سراسری نیست بلکه یک فرآیند کاملا شفاف برای بروز رسانی state برنامه است. اینجاست که وارد بحث Action ها می شویم. Action ها از سمت کامپوننت های شما ارسال می شوند و در عمل پکیج های اطلاعاتی هستند که از قبل تعریف شده اند. این Action ها دارای دستورات خاصی به نام type هستند مثلا add ingredient (یعنی محتویات را اضافه کن) و در برخی اوقات دارای payload است یعنی اگر می گوییم add ingredient (محتویات را اضافه کن) در ادامه مشخص کنیم که کدام محتویات را اضافه کند، گوشت؟ پنیر؟ سالاد؟ به همین دلیل است که می گوییم Action ها پکیج های اطلاعات هستند که به redux ارسال می شوند و هیچ منطق برنامه نویسی ندارند و نمی دانند چطور State را بروز رسانی کنند.
در این مرحله به عنصری نیاز داریم که اطلاعات action را دریافت کرده و روی state اعمال کند. به این عنصر خاص reducer (به معنی «کاهش دهنده») می گوییم. البته شما می توانید چندین reducer داشته باشید اما در نهایت یک reducer ریشه ای دریافت می کنید که مستقیما به آن نقطه مرکزی redux متصل است که حاوی state شما می باشد. Reducer ها type (نوع دستور ارسالی) را چک می کنند (مثلا add ingredient) بنابراین ما کدهای مورد نظر برای اجرا را درون reducer می نویسیم تا منطق مثلا add ingredient (اضافه کردن محتویات) را پیاده سازی کنید. در نهایت reducer یک تابع است که action و State قدیمی را دریافت می کند و سپس state جدید را برمی گرداند. باید توجه داشته باشید که اجرای کدهای reducer فقط به صورت synchronous (همگام) است بنابراین هیچ side-effect و درخواست HTTP را نخواهیم داشت. البته بعدا راه های ایجاد درخواست ناهمگام را یاد خواهیم گرفت اما خود reducer فقط کد را می گیرد و نتیجه را پس می دهد. در مرحله نهایی reducer کد state جدید را به مرکز اصلی redux می فرستد و state بروز رسانی می شود.
برای دریافت state جدید در کامپوننت های خودمان از مفهومی به نام مدل های subscription استفاده می کنیم. هر زمانی که state تغییر کند، مرکز اصلی redux نیز این subscription ها را فعال می کند. در واقع subscription ها به کامپوننت های شما متصل هستند و بروز رسانی های جدید را به صورت props به کامپوننت هایتان پاس می دهند. همانطور که گفتم هر زمان که state تغییر کند، این subscription ها نیز فعال شده و تغییرات را به صورت خودکار به کامپوننت های شما ارسال خواهند کرد.
این مدل نحوه کار redux را به خوبی توضیح می دهد و امیدوارم شما هم این جریان کاری را درک کرده باشید. البته این در مقاله redux را از نحوه تئوری بررسی کردیم و در قسمت بعد از redux به صورت عملی استفاده خواهیم کرد.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.