مفاهیم پایه ریداکس — راهنمای مقدماتی

۱۷۲ بازدید
آخرین به‌روزرسانی: ۰۳ مهر ۱۴۰۲
زمان مطالعه: ۶ دقیقه
مفاهیم پایه ریداکس — راهنمای مقدماتی

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

ریداکس بر مبنای Flux (+) است. Flux یک معماری اپلیکیشن برای ساخت اینترفیس های کاربری است که از گردش داده غیر جهت‌دار پشتیبانی می‌کند. Flux از سوی فیسبوک ساخته شده است و ریداکس یک کتابخانه محبوب است که بر مبنای مفاهیم معرفی شده در Flux ساخته شده است.

می‌توان از ریداکس برای مدیریت داده‌ها روی یک صفحه ساده جاوا اسکریپت استفاده کرد. در این حالت هیچ کتابخانه دیگری مورد نیاز نیست. نکته خوب این است که اگر صرفاً می‌خواهید آن را بررسی کنید به هیچ مرحله راه‌اندازی نیاز ندارد. کافی است تگ <script> را روی صفحه قرار دهید که به ریداکس اشاره کند و کار تمام است. این همان کاری است که می‌خواهیم در این راهنما انجام دهیم. در این راهنما قصد داریم مفاهیم پایه‌ای که برای ایجاد یک استور ریداکس برای مدیریت هتل لاسم است بدانید را با هم مرور می‌کنیم.

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

چرا باید ریداکس را یاد بگیریم؟

ریداکس موجب می‌شود که زندگی ما آسان‌تر شود و با آن کارهای زیر را انجام می‌دهیم:

  • حالت اپلیکیشن را ذخیره می‌کنیم.
  • حالت اپلیکیشن را مدیریت می‌کنیم.
  • تغییرات حالت اپلیکیشن را به بخش‌هایی که مورد نیاز است اطلاع می‌دهیم.

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

ریداکس مبتنی بر 3 اصل اساسی است:

  1. همه داده‌های اپلیکیشن در یک شیء حالت منفرد به نام state یا state tree ذخیره می‌شوند.
  2. حالت صرفا-خواندنی است. تنها روش تغییر آن dispatch کردن یک اکشن روی استور است.
  3. برای توصیف تغییرهای حالت باید تابعی بنویسید که حالت کنونی و اکشنی که باید اجرا شود را بگیرد. این تابع باید یک حالت به‌روزشده جدید بازگشت دهد و نه نسخه‌ای از حالت موجود. این تابع‎ها به نام «ریدوسر» (Reducers) خوانده می‌شوند.

بخش‌های ریداکس

در این مرحله، بخش‌های مختلف ریداکس را بررسی می‌کنیم.

استور

«استور» (Store) جایی است که حالت اپلیکیشن را ذخیره می‌کنیم. استور به طرز خارق‌العاده‌ای ساده است و کارهای مختلفی انجام می‌دهد:

  1. حالت را ذخیره می‌کند.
  2. دسترسی به حالت می‌دهد.
  3. حالت را به‌روزرسانی می‌کند.
  4. فهرستی از بخش‌های درگیر (یعنی شنونده‌ها) نگهداری می‌کند. زمانی که یک رویداد رخ می‌دهد، حالت را تغییر می‌دهد و این تغییر را به این بخش‌های درگیر اطلاع می‌دهد.

این‌ها همه وظایف استور را شامل می‌شوند.

اکشن‌ها

«اکشن‌ها» (Actons) اشیای ساده جاوا اسکریپت هستند که برای ارسال اطلاعاتی از اپلیکیشن به استور استفاده می‌شوند. اکشن‌ها تنها منبع اطلاعات برای استور محسوب می‌شوند.

در ادامه مثالی از یک اکشن می‌بینید:

1{
2  type: 'CHECK_IN',
3  dog: dog
4}

اکشن‌ها باید یک مشخصه type داشته باشند. در این کد مشخصه type روی CHECK_IN تنظیم شده است. در ادامه با روش استفاده از این مشخصه آشنا می‌شویم. داشتن تابعی که بتواند یک شیء اکشن برای ما ایجاد کند مفید خواهد بود. این تابع‌ها به طرز مناسبی به نام تابع‌های Action Creator خوانده می‌شوند. در ادامه چند تابع Action Creator تعریف می‌کنیم که در اپلیکیشن هتل ما مورد استفاده قرار می‌گیرند:

1// Action Creator Functions
2const checkIn = (name, spaTreatment = false) => {
3  return {
4    type: 'CHECK_IN',
5    dog: new Dog(name, spaTreatment)
6  }
7}
8const checkOut = (dog) => {
9  return {
10    type: 'CHECK_OUT',
11    id: dog.id
12  }
13}

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

Reducer

ریدوسر تابع است. ریدوسر حالت قبلی و یک شیء اکشن به عنوان آرگومان می‌گیرد و حالت بعدی را بازگشت می‌دهد.

تابع‌های ریدوسر باید «تابع‌های خالص» (Pure Functions) باشند.

منظور از تابع خالص، تابعی است که یک ورودی یکسان همواره خروجی یکسانی ایجاد می‌کند. برای نمونه تابع زیر یک تابع خالص است، زیرا اگر ورودی یکسانی (مثلاً عدد 10) به آن بدهیم، همواره مقدار 30 بازگشت می‌دهد. تابع خالص به هیچ حالت خارجی وابسته نیست و هیچ فراخوانی API نیز ندارد.

1const myPureFunc = (a) => (a * 2);

با این حال تابع زیر یک تابع خالص محسوب نمی‌شود:

1var theNumber = 10;
2const notPureFunc = (a) => (theNumber * a);

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

اگر مدتی با جاوا اسکریپت کار کرده باشید، با تابع ()Array.prototype.reduce آشنا هستید. هیچ موردی وجود ندارد که این ویژگی ریداکس، به صورت Reducer خوانده شده باشد. امضای یک تابع Reducer در ریداکس نیز مشابه ()Array.prototype.reduce است. امضای ریدوسر ریداکس به صورت زیر است:

1(previousState, action) => nextState

امضای Array.prototype.reduce نیز چنین است:

1(accumulator, value) => (accumulator + value)

امضاها یکسان هستند و از این رو یا مفهومی کار می‌کنیم که از قبل آشنا هستیم. همچنین بهتر است بدانیم که اگر از Array.prototype.reduce در گذشته استفاده کرده باشیم، مفهوم ریدوسر در ریداکس برای ما آشنا خواهد بود. در ادامه تابع ریدوسر را در اپلیکیشن هتل خود می‌بینیم:

1//setup initial state for the store
2const initialState = {
3    dogs: []
4}
5
6//Reducers
7function dogHotelApp(state = initialState, action) {
8    switch (action.type) {
9        case 'CHECK_IN':
10            return Object.assign({}, state, {
11                dogs: [...state.dogs, action.dog]
12            })
13        case 'CHECK_OUT':
14            return state.dogs.filter(d => d.id !== action.id);
15        default:
16            return state;
17    }
18}
19
20// In redux, all app state is stored as a single store object
21let store = Redux.createStore(dogHotelApp);
22
23// check what the state is right after store creation
24console.log(store.getState());
25
26// if we want to stop receiving noifications we can use the unsub() function 
27// that is returned from store.subscribe()
28const unsub = store.subscribe(() => console.log(store.getState()));
29
30// lets have a few dogs check-in
31store.dispatch(checkIn('penny', true));
32store.dispatch(checkIn('molly', true));
33store.dispatch(checkIn('rover', true));
34store.dispatch(checkIn('winston', true));
35store.dispatch(checkIn('buster', true));
36
37
38//lets have molly check out
39store.getState().dogs.forEach(dog => {
40    if (dog.name === 'molly') {
41        boundCheckOut(dog);
42    }
43});

در کد فوق نخستین چیزی که در خط 1 تا 4 انجام می‌دهیم ایجاد یک شیء جاوا اسکریپت است که به عنوان حالت اولیه استفاده خواهد شد. می‌دانیم که اپلیکیشن قرار است برای مدیریت افرادی که به هتل وارد و از آن خارج می‌شوند استفاده شود. از این رو به یک آرایه برای ذخیره‌سازی آن‌ها نیاز داریم.

در خط 7 یک ریدوسر تعریف می‌کنیم. این ریدوسر حالت و اکشن را به عنوان آرگومان می‌گیرد.

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

اگر مقدار مشخصه type به صورت CHECK_IN باشد، یک شیء جدید با استفاده از Object.assign ایجاد می‌کنیم و آن را به حالت جدید بازگشت می‌دهیم. توجه داشته باشید که حالتی که ارسال شده را تغییر نمی‌دهیم و یک شیء جدید ایجاد خواهیم کرد. از مشخصه‌های شیء ارسالی برای تنظیم شیء جدید استفاده می‌کنیم و سپس مهمان جدید را به آرایه ورودی‌های هتل الحاق می‌کنیم.

اگر مشخصه CHECK_OUT باشد، صرفاً از Array.filter برای بازگشت دادن همه موارد به جز مهمان‌های تطبیق یافته استفاده می‌کنیم. توجه کنید که Array.filter آرایه dogs[]‎ را درجا ویرایش کرده و بازگشت نمی‌دهد. dogs[]‎ یک آرایه جدید بازگشت می‌دهد، چون نمی‌توانیم حالت را درون تابع ریدوسر ویرایش کنیم.

در نهایت در خط 21 یک استور جدید می‌سازیم و از آن با ایجاد برخی فراخوانی‌ها برای تست کارکرد بهره می‌گیریم. نتیجه‌ای که در کنسول به دست می‌آید به صورت زیر است:

مفاهیم پایه ریداکس

اینک پنج میهمان داریم که وارد هتل شده‌اند و یک میهمان آن را ترک کرده است.

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

  • ()Redux.createStore – استور را ایجاد می‌کند.
  • ()store.dispatch – پیام اکشن را به استور می‌فرستد.
  • ()store.getState – حالت کنونی استور را دریافت می‌کند.
  • ()store.subscribe – برای آگاه شدن از تغییراتی که در حالت رخ می‌دهند ثبت نام می‌کند.

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

نکات پایانی

در این بخش برخی مواردی که در این راهنما مطرح شد را جمع‌بندی می‌کنیم:

  1. ریداکس یک کانتینر حالت پیش‌بینی‌پذیر برای اپلیکیشن‌های جاوا اسکریپت است.
  2. ریداکس بر مبنای Flux است که یک معماری اپلیکیشن برای ساخت اینترفیس‌های کاربری است. Flux توسط فیسبوک ساخته شده است.
  3. ریداکس لزوماً همراه با ری‌اکت استفاده نمی‌شود.
  4. ریداکس بر مبنای 3 اصل اساسی کار می‌کند.
    1. همه داده‌های اپلیکیشن در یک شیء حالت منفرد نگهداری می‌شوند که حالت یا درخت حالت نام دارد.
    2. حالت صرفا-خواندنی است و تنها با توزیع یک اکشن روی استور تغییر می‌یابد.
    3. برای توصیف تغییر حالت باید یک تابع بنویسیم که حالت کنون و اکشنی که باید اجرا شود را بگیرد. تابع باید یک حالت به‌روزرسانی شده جدید بازگشت دهد و نه یک نسخه ویرایش شده از حالت موجود. این تابع‌ها به نام ریدوسر نامیده می‌شوند.
  5. همه تابع‌های ریدوسر باید تابع‌های خالص باشند.

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

اگر این مطلب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

==

بر اساس رای ۰ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
dailyjs
نظر شما چیست؟

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