ماژولار کردن مدیریت State در VueX

Modify State Management in VueX

Vue.JS 2: ماژولار کردن مدیریت state در VueX - قسمت 98

با انواع مختلفی از مباحث VueX آشنا شده ایم اما یکی از بحث های فرعی در VueX مبحث ماژولار کردن مدیریت State است که در برنامه های بزرگ کاربرد دارد. فرض کنید در یک برنامه بسیار بزرگ تمام state ها و mutation ها و action ها و getter ها درون یک فایل باشند! این فایل بسیار بزرگ خواهد بود و نظمی نخواهد داشت. برای انجام این کار ابتدا در پوشه store یک پوشه دیگر به نام modules ایجاد کنید.

در بسیاری از مواقع کدهای داخل store.js را می توان به دسته های منطقی تقسیم کرد. مثلا در فایل خودمان کدهای مربوط به counter.vue شامل counter در state و متد های doubleCounter و غیره هستند اما value فقط در App.vue استفاده می شود. البته در برنامه کوچک ما انجام چنین تقسیمی، کاری منطقی نیست اما من این کار را به خاطر اهداف آموزشی انجام می دهم. بنابراین بهتر است فایل Store.js را به دو ماژول تقسیم کنیم. برای این کار به پوشه modules بروید و دو فایل دیگر به نام های counter.js و value.js ایجاد کنید. حالا به counter.js بروید و یک ثابت به نام State را تعریف می نماییم:

const state = {
    counter: 0
};

دیگر value را در اینجا نمی آوریم چرا که این فایل مخصوص counter (شمارنده) است. همین کار را با دیگر اجزای counter انجام می دهیم تا فایل این فایل (counter.js) به شکل زیر در بیاید:

const state = {
    counter: 0
};

const getters = {
    doubleCounter: state => {
        return state.counter * 2;
    },
    stringCounter: state => {
        return state.counter + ' Clicks';
    }
};

const mutations = {
    increment: (state, payload) => {
        state.counter += payload;
    },
    decrement: (state, payload) => {
        state.counter -= payload;
    }
};

const actions = {
    increment: ({ commit }, payload) => {
        commit('increment', payload);
    },
    decrement: ({ commit }, payload) => {
        commit('decrement', payload);
    },
    asyncIncrement: ({ commit }, payload) => {
        setTimeout(() => {
            commit('increment', payload.by);
        }, payload.duration);
    },
    asyncDecrement: ({ commit }, payload) => {
        setTimeout(() => {
            commit('decrement', payload.by);
        }, payload.duration);
    }
}

من تک تک قسمت های مربوط به counter را از فایل store.js را برداشته و در این فایل قرار داده ام. البته کار سازماندهی را به شیء های مختلفی واگذار کرده ام تا state و mutation و getter و action ها همگی در شیء های جداگانه ای باشند. در نهایت دو راه برای استفاده از این اشیاء داریم:

  • یا کدها را طوری ویرایش کنیم که هر شیء را export کنیم. در این حالت برای استفاده از هر شیء باید آن را import کنیم.
  • یا کدها را طوری بنویسیم که فقط یک شیء کلی برای export داشته باشیم. در این حالت فقط کافی است همان شیء را import کنیم.

هر عقل سلیمی می پذیرد که روش دوم بسیار ساده تر است بنابراین می توان گفت:

// بقیه کدها //
const actions = {
    increment: ({ commit }, payload) => {
        commit('increment', payload);
    },
    decrement: ({ commit }, payload) => {
        commit('decrement', payload);
    },
    asyncIncrement: ({ commit }, payload) => {
        setTimeout(() => {
            commit('increment', payload.by);
        }, payload.duration);
    },
    asyncDecrement: ({ commit }, payload) => {
        setTimeout(() => {
            commit('decrement', payload.by);
        }, payload.duration);
    }
}

export default {
    state: state,
    mutations: mutations,
    actions: actions,
    getters: getters
}

همانطور که در کد بالا مشخص است من یک دستور export default را برای یک شیء نوشته ام تا این فایل فقط و فقط یک دستور Export داشته باشد. درون این شیء کلید های state و mutation و getter و action را داریم که مقادیرشان همان اشیاء state و mutation و getter و action است. آیا یادتان هست که در چنین شرایطی می توانستیم از حالت خلاصه ES6 استفاده کنیم؟

export default {
    state,
    mutations,
    actions,
    getters
}

حالا کد ما تمیزتر شده است! فعلا این کار را برای فایل value.js انجام نمی دهیم چرا که می خواهم بعدا چیزی را به شما نشان بدهم که به این فایل مربوط است. حالا باید شیء export شده در counter.js را وارد store.js کنیم چرا که همیشه فایل state ما یک فایل واحد خواهد بود. احتمالا فکر می کنید که باید به صورت دستی تمام این اشیاء را import کنیم اما اینطور نیست. تنها کار لازم رفتن به فایل Store.js و تعریف خصوصیت جدیدی به نام modules است:

import Vue from 'vue';
import Vuex from 'vuex';
import counter from "./modules/counter";

Vue.use(Vuex);

export const store = new Vuex.Store({
    state: {
        counter: 0,
        value: 0
    },
    getters: {
        value: state => {
            return state.value;
        }
    },
    mutations: {
        updateValue: (state, payload) => {
            state.value = payload;
        }
    },
    actions: {
        updateValue({ commit }, payload) {
            commit('updateValue', payload);
        }
    },
    modules: {
        counter
    }
});

من کل کدهای فایل store.js را برایتان قرار داده ام تا ببینید بعد از کات کردن تمام خصوصیات مربوط به counter.vue و قرار دادن آن ها در counter.js، این فایل به چه شکلی در آمده است. من در ابتدا فایل counter.js را در این فایل import کرده ام. سپس یک خصوصیت جدید را در انتهای این فایل تعریف کرده ام که modules نام دارد. تمام این نام ها باید دقیقا به همین شکل باشد و نمی توانید آن ها را تغییر بدهید. تنها چیزی که به modules داده ام همان counter ای است که در بالای صفحه import کرده بودم. در ضمن من در این قسمت از روش خلاصه ES6 استفاده کرده ام که خلاصه کد زیر است:

// بقیه کدها //
    actions: {
        updateValue({ commit }, payload) {
            commit('updateValue', payload);
        }
    },
    modules: {
        counter: counter
    }
});

اما من همان حالت خلاصه را استفاده می کنم. حالا اگر کدها را ذخیره کرده و به مرورگر بروید، همه چیز بدون مشکل اجرا می شود.

نوبت به معرفی مشکل جدید می رسد! تصور کنید که دو ماژول برای State داریم: پست های سایت و کاربران سایت. حالا اگر کدهایی داشته باشیم که به هیچ کدام از این ماژول ها مربوط نباشند و از طرفی نخواهیم آن ها را در store.js قرار بدهیم چطور؟ مثلا کدهایی مربوط به header صفحه که باید در همه جا باشند. یا به هر دلیل دیگری بخواهیم تقسیم بندی متفاوتی داشته باشیم (نه اینکه همیشه ماژول هایمان را بر اساس کامپوننت ها ایجاد کنیم). من یک فایل دیگر در پوشه Store ایجاد می کنم که actions.js نام دارد. سپس تنها action خودم را که مربوط به value است (updateValue) به شکل زیر در این فایل قرار می دهم:

 export const updateValue = ({ commit }, payload) => {
    commit('updateValue', payload);
}

اگر action های دیگری نیز داشتید، آن ها را بدین شکل export می کنید (هر Action یک export جداگانه دارد). حالا به Store.js برمی گردیم و برای import کردن actions.js می گوییم:

import Vue from 'vue';
import Vuex from 'vuex';
import counter from "./modules/counter";

import * as actions from "./actions";

درست است که ما در این برنامه کوچک فقط یک Action داریم اما در برنامه های بزرگ تر قطعا بیشتر از این تعداد action خواهیم داشت و به جای وارد کردن تک تک آن ها می توانیم از علامت * و سپس as actions استفاده نماییم. با این کار جاوا اسکریپت یک شیء به نام actions می سازد که تمام export های فایل Actions.js را درون خود دارد. سپس به قسمت پایین تر این فایل (store.js) می روم و می گویم:

// بقیه کدها //
    mutations: {
        updateValue: (state, payload) => {
            state.value = payload;
        }
    },
    actions,
    modules: {
        counter: counter
    }
});

باز هم از روش خلاصه ES6 استفاده کرده ام و تمام action ها را به شکل بالا وارد این قسمت کرده ام. همین کار را با mutation ها نیز انجام می دهیم. یعنی یک فایل به نام mutations.js را درون پوشه store (نه پوشه modules) می سازم و آن را به شکل زیر قرار می دهم:

export const updateValue = (state, payload) => {
    state.value = payload;
}

سپس فایل دیگری برای getter ها به نام getters.js:

export const value = state => {
    return state.value;
}

در نهایت در Store.js این فایل ها را import کرده و از آن ها استفاده می کنیم:

import Vue from 'vue';
import Vuex from 'vuex';
import counter from "./modules/counter";

import * as actions from "./actions";
import * as getters from "./getters";
import * as mutations from "./mutations";

Vue.use(Vuex);

export const store = new Vuex.Store({
    state: {
        counter: 0,
        value: 0
    },
    getters,
    mutations,
    actions,
    modules: {
        counter: counter
    }
});

حالا همه چیز مثل قبل کار می کند اما فایل هایمان به شدت ساختار یافته و منظم شده اند.

windows 8.1 enterprise lizenz kaufen

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری آموزش رایگان Vue js از صفر تا صد توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.