image


При написании больших фронтенд-приложений управление состоянием может стать довольно сложной и утомительной задачей.


image


Для Vue.js был разработан плагин Vuex, предназначенный для управления состоянием. По умолчанию в нем выстроена следующая структура папок:


image
Структура папок в хранилище Vuex


Эту структуру папок можно было бы использовать в небольших приложениях, но в больших исходный код, скорее всего, будет выглядеть нечитаемо и некрасиво, а со временем с ним станет тяжело работать.


image
О да, я узнал это на собственном горьком опыте


Я бы рекомендовал структуру папок, в которой хранилище разбито на различные модули. Например:


image
Рекомендованная структура Vuex (прим. пер.: на этой картинке автор, вероятно, забыл добавить файл store/modules/user/mutations.js, т.к. он фигурирует далее в коде)


Эта структура папок разбивает хранилище на модули, у каждого из которых есть своя отдельная папка. Папка со всеми модулями находится там же, где и index.js, сгенерированный с помощью Vuex. Как и следовало ожидать, содержимое файла index.js нужно тоже поменять, например на такое:


import Vue from "vue";
import Vuex from "vuex";
import state from './state.js'
import actions from './actions.js'
import mutations from './mutations.js'
import getters from './getters.js'
import user from './modules/user/index.js'
Vue.use(Vuex);
export default new Vuex.Store({
    state,
    mutations,
    actions,
    getters,
    modules: {
        user
    }
});

В этом примере я создал модуль «user», импортировал его в index.js, предоставленный библиотекой Vuex. Таким образом, модуль «user» был подключен к хранилищу, и теперь доступен.


Переходя к модулю «user» мы импортируем state, actions, getters и mutations в modules/user/index.js таким образом:


import state from './state.js'
import mutations from './mutations.js'
import actions from './actions.js'
import getters from './getters.js'
export default {
    namespaced: true,
    state,
    mutations,
    getters,
    actions,
}

Если вы заметили, полю namespaced было задано значение true. Это обусловлено тем, что в определенных обстоятельствах мы хотим иметь возможность указать, чтобы определенный модуль искал определенное действие, состояние или геттер. Идем дальше...


Состояние


Из-за перехода от стандартной структуры Vuex к модульной методы, через которые мы получали доступ к состоянию Vuex, нужно изменить. Например, мы не сможем получить доступ к полю userAvatar из состояния модуля «user» простым отображением поля userAvatar на поля объекта вычисляемых свойств (прим. пер.: под простым отображением понимается такой стандартный способ вызова функции mapState: ...mapState(['userAvatar'])}). Так что мы используем функцию mapState (прим. пер.: эта функция автоматически генерирует вычисляемые свойства) в скрипте компонента следующим образом:


import {mapState} from 'vuex'
export default {
    computed: {
        ...mapState({
            userAvatar: state => state.user.userAvatar
        })
    },
}

Выше показан рекомендованный метод получения доступа к состоянию модуля, которое бы выглядело так:


export default {
    userAvatar: "img-location"
};

Действия


Также нельзя ожидать, что действие из модуля «user» будет доступно простым отображением действий на поля объекта методов. Нам бы пришлось указать конкретный модуль, к которому мы пытаемся получить доступ, например:


import {mapActions} from 'vuex'
export default {
    methods: {
        ...mapActions("user", ["getUserInfo"]),
        userInfo() {
            this.getUserInfo()
            // вы могли бы либо отобразить это – как мы сделали выше (прим. пер.: вероятно, имеется в виду строчка <..mapActions("user", ["getUserInfo"]),>), либо вызвать в точности тем же способом, 
            // что использован ниже
            this.$store.dispatch('user/getUserInfo')
            // эти два метода выполняют одну и ту же задачу – вызов действия getUserInfo
        }
    },
}

Выше представлен предпочтительный метод доступа к действию из модульного Vuex в случае использования следующего файла с действиями:


export default {
    getUserInfo() {
        alert('Successful')
    }
}

Мутации


Мутации используются для синхронных функций и чаще всего используются для изменения состояния. Способ получения доступа к мутации также будет другим.


export default {
    methods: {
        setuserInfo() {
            let data = {
                name: 'Henry'
            }
            this.$store.commit('user/setUserInfo', data)
        }
    },
}

Выше представлен рекомендованный способ доступа к мутации в модульном Vuex при использовании такого файла с мутациями:


export default {
    setUserInfo: (state, data) => {
        state.user = data
    }
}

Геттеры


Геттеры подобны вычисляемому свойству компонента. Их используют для вычислений или фильтрации. Типичный случай использования геттеров – сортировка по отличиям в полях или по доступности полей, например:


export default {
    getActiveUsers: state => {
        return state.users.filter(x => x.active === true)
    }
}

Выше – рекомендованный способ объявления или записи геттера, при этом к нему можно получить доступ с помощью отображения геттеров на поля объекта вычисляемых свойств, например вот так:


import {mapState} from 'vuex'
export default {
    computed: {
        ...mapGetters('user', ['getActiveUsers'])
    },
}

Это был долгий путь, надеюсь, что у вас получилось использовать модульный Vuex и писать более чистый код.