Vuex-models - простой способ научить vuex работать с v-model
О том, как легко и непринуждённо можно создавать реактивные поля в vuex store и столь же просто использовать их в ваших компонентах.
Основная идея в Vuex - ограничение доступа к прямому изменению состояния. Т.е. по хорошему, вы не можете взять store.state и менять в нём значения вручную (можете, без strict, конечно, но, пожалуйста, не делайте так) — вместо этого, вы создаёте action для получения/обработки данных, mutation - для непосредственной записи значения в store. Также, хорошим тоном будет создать getter для получения этих значений.
Сама по себе парадигма невероятно удобна, но если в вашем приложении используется очень много однотипных свойств в 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