Tominoff S.

Frontend / Backend developer

Vuex-models - простой способ научить vuex работать с v-model

О том, как легко и непринуждённо можно создавать реактивные поля в vuex store и столь же просто использовать их в ваших компонентах.

Основная идея в Vuex - ограничение доступа к прямому изменению состояния. Т.е. по хорошему, вы не можете взять store.state и менять в нём значения вручную (можете, без strict, конечно, но, пожалуйста, не делайте так) — вместо этого, вы создаёте action для получения/обработки данных, mutation - для непосредственной записи значения в store. Также, хорошим тоном будет создать getter для получения этих значений.

 

Общая схема работы vuex

 

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

 

Кроме того, если вам нужны реактивные возможности v-model — для каждого свойства придётся писать вычислимые (computed) свойства, у которых геттеры (get) будут получать данные из стейта, а сеттеры (set) — вызывать мутации.

 

В перспективе — это тонны однотипного кода и в описании ваших vuex store, и в computed свойствах компонентов.

 

Я столкнулся с этой проблемой при разработке opencart модуля foc_csv — количество реактивных полей в интерфейсе, даже на начальной стадии, было довольно велико, и в процессе разработки их должно было становиться всё больше.

 

Чтобы как-то автоматизировать рутину с vuex — я создал пару удобных функций, которые затем, в усовершенствованном виде и легли в основу библиотеки vuex-models.

 


 

vuex-models

Библиотека предоставляет всего лишь две функции — genVuexModels и mapVuexModels.

 

genVuexModels — получает на входе список моделей (полей в state), а также, опционально, название переменной в state куда будут сохраняться значения моделей (по умолчанию — vxm).

 

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

 

/*
  Генерируем модели (будут созданы actions, mutations, getters для поля)
*/
const models = genVuexModels({
  modelName: 'defaultValue',
  foo: {
    bar: 'baz'
  }
  // второй аргумент задаёт название поля в state,
  // если передать false, то генерируемые поля будут добавляться в state напрямую
}, 'featureStateVariable')

 

Объект models будет содержать полный набор необходимых свойств — state,mutations,actions,getters, в самом простом случае их можно добавить в ваши vuex модули с помощью spread-оператора. 

Вообще можно добавить их прямо в store (если у вас простенькое приложение), но я рекомендую всё же использовать модули для этого.

const featureModule = {
  namespaced: true,
  ...models
}

const store = new Vuex.Store({
  modules: {
    featureNamespace: featureModule
  }
}) 

 

Вот и весь процесс генерации моделей. Серьёзно!

 

Следующий шаг — добавление этих моделей в ваши vue компоненты. Делается это с помощью функции mapVuexModels:

 

import { mapVuexModels } from 'vuex-models'

return {
  computed: {
    ...mapVuexModels({
      model: 'modelName',
      foo: 'foo'
    }, 'featureNamespace') // если вы не используете vuex модули, то не передавайте этот аргумент
  }
}

 

Второй аргумент функции опционален, используйте его в том случае, если ваши модели находятся в namespaced модулях vuex (использование модулей — это рекомендуемый способ).

 

Теперь вы можете использовать свойства model и foo как обычные вычислимые свойства vue, поскольку mapVuexModels генерирует объекты с getter/setter следующего вида:

 

get () { return this.$store.getters['<PATH_TO_MODEL>_<MODEL_NAME>'] }
set (val) { this.$store.dispatch('set<PATH_TO_MODELS>_<MODEL_NAME>', val)

 

Таким образом эти свойства можно спокойно использовать в v-model без риска создания побочных эффектов:

 

<input v-model="foo">

 

Где взять?

 

Библиотека оформлена как npm пакет — https://www.npmjs.com/package/vuex-models

Также, очень приветствуются замечания и pull-реквесты — https://github.com/ikenfin/vuex-models