Мощный модуль для типизации Vuex

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

Мотивом для написания данной статьи послужила другая статья на тему типизации Vue и, соответственно, Vuex. К моему удивлению я не обнаружил там упоминания модуля, который, по моему мнению, является лучшим в своем роде «типизатором» Vuex. Поиск по Хабру, да и вообще по Рунету (на самом деле и в англоязычных источниках не просто сходу найти какие-либо упоминания), увы, не дал никаких результатов. Данная статья не является подробным разбором и многостраничным мануалом по использованию и настройке, но скорее способом поделиться с вами, уважаемые Vue-ниндзя, инструментом, который отлично справляется со своей задачей.

vuex-smart-module


У кого совсем нет времени: Github.

Главное предназначение модуля, как вы успели догадаться, — это полноформатное покрытие хранилища Vuex типами. Как внутри, так и непосредственно в самих компонентах. Модуль написан основным контрибьютором (@ktsn) библиотек Vuex и vue-class-component.

Вода


Признаться, мой путь в Typescript начался еще совсем недавно, в т.ч. и с такими штуками как декораторы, потому не могу сравнить данную библиотеку с другими аналогами. Мои попытки настроить и использовать другие инструменты (например vuex-module-decorators) приводили меня к разным проблемам, которые в итоге так или иначе не позволяли реализовать то, что мне было нужно (либо я просто, как говориться, не умел их готовить). С vuex-smart-module мне очень повезло — библиотека появилась именно в тот момент, когда я переводил проект (и хранилище) на Typescript. Теперь все отлично работает, а код радует глаз.

Примеры


У библиотеки, на мой взгляд, хорошая документация, которая покрывает все возможные случаи с которым вам придется столкнуться (а если нет — то в тестах можно найти все остальное, нетривиальное). Однако, чтобы хоть как-то разбавить статью кодом, приведу базовые примеры подключения и использования, пару примеров «из жизни», а так же как это работает в связке с декораторами (там есть нюанс).

Создание модуля


Создается модуль при помощи классов. Некоторым это может показаться непривычно отпугивающим, но поверьте, привыкаешь быстро.

store/root.ts
// Импорт базовых классов
import { Getters, Mutations, Actions, Module } from 'vuex-smart-module'

// Стейт
class RootState {
  count = 1
}

// Геттеры
// Необходимо расширить класс типами из RootState
class RootGetters extends Getters<RootState> {
  get double() {
    // У инстанса геттера есть свойство `state`
    return this.state.count * 2
  }

  get triple() {
    // Для использования других геттеров есть свойство `getters`
    return this.getters.double + this.state.count
  }
}

// Мутации
// Так же как и геттеры, класс мутаций расширяется типами RootState
class RootMutations extends Mutations<RootState> {
  increment(payload: number) {
    // У мутаций так же есть свойство `state`
    this.state.count += payload
  }
}

// Действия
// Здесь аналогично расширяется класс
// Но есть один нюанс, класс нужно расширить типами этого же класса, явно указав это в параметрах
class RootActions extends Actions<
  RootState,
  RootGetters,
  RootMutations,
  RootActions
> {
  incrementAsync(payload: { amount: number; interval: number }) {
    // У инстанса действия есть свойства `state`, `getters`, `commit` и `dispatch` 
    return new Promise(resolve => {
      setTimeout(() => {
        this.commit('increment', payload.amount)
      }, payload.interval)
    })
  }
}

// Экспорт модуля
export default new Module({
  state: RootState,
  getters: RootGetters,
  mutations: RootMutations,
  actions: RootActions
})


Подключение


/store/index.ts
import Vue from 'vue'
import * as Vuex from 'vuex'
import { createStore } from 'vuex-smart-module'
import RootStore from './root'

Vue.use(Vuex)

export const store = createStore(
  RootStore,
  {
    strict: process.env.NODE_ENV !== 'production'
  }
)


Модули


Подключение модулей аналогично тому, как это происходит в обычном Vuex. Их нужно указать в свойстве modules у RootStore:


import FooStore from './modules/foo'

/* … */

export default new Module({
  state: RootState,
  getters: RootGetters,
  mutations: RootMutations,
  actions: RootActions,
  modules: {
    FooStore
  }
})


Использование внутри компонента


Пользоваться стором можно как через глобальное свойство this.$store, так и через мэппинг, который во многом похож на тот, что есть во Vuex:


import Vue from 'vue'

// Импорт корневого стора (тоже самое и с любым другим модулем)
// import FooStore from '@/store/modules/foo'
import RootStore from '@/store/root'

export default Vue.extend({
  computed: RootStore.mapGetters(['double']),

  methods: RootStore.mapActions({
    incAsync: 'incrementAsync'
  }),

  created() {
    console.log(this.double)
    this.incAsync(undefined)
  }
})


Приемы


Подлюкчение с использованием декораторов (vue-property-decorator)


import { Vue, Component } from "vue-property-decorator"

// Импорт корневого стора (тоже самое и с любым другим модулем)
// import FooStore from '@/store/modules/foo'
import RootStore from "@/store/root"

// Обратите внимание, что для того, чтобы все заработало в рамках Typescript, необходимо расширить класс таким образом:
const Mappers = Vue.extend({
  computed: {
    ...RootStore.mapGetters(["double"])
  },
  methods: {
    ...RootStore.mapActions({
      incAsync: 'incrementAsync'
    })
  }
});

@Component
export default class MyApp extends Mappers {
  created() {
    console.log(this.double)
    this.incAsync(undefined)
  }
}

Использование модуля внутри модуля


/store/module/bar.ts
import { Store } from 'vuex'
import { Getters, Actions, Module, Context } from 'vuex-smart-module'

// Импорт другого модуля
import FooStore from './foo'

/* … */

class BarGetters extends Getters {
  // Объявление контекста
  foo!: Context<typeof FooStore>;

  // Вызывается посли инициализации модуля
  $init(store: Store<any>): void {
    // Создание и сохранение контекста
    this.foo = FooStore.context(store)
  }

  get excited(): string {
    return this.foo.state.value + '!' // -> hello!
  }
}

/* … */


Сброс хранилища


Иногда может потребоваться сбросить хранилище на значения по умолчанию, делается это довольно просто:
class FooState {
  /* ... */
}

class FooMutations extends Mutations<FooState> {
  reset () {
      const s = new FooState()
      Object.keys(s).forEach(key => {
        this.state[key] = s[key]
      })
  }
}


Финал


Надеюсь, что вам было интересно, ну или, по крайней мере, вы узнали об этой библиотеке. Кто знает, может быть начиная со следующего проекта (а может быть и рефакторинг текущих не за горами?) вы начнете, как и я, использовать vuex-smart-module (или вообще Typescript в целом)? Лично мой переход на Typescript был довольно болезненным (за 1.5-2 года я принимался за попытки перейти на него раза 3-4 минимум, но каждый раз упирался в какие-то проблемы, непонимание. Меня часто преследовало ощущение, что разработка на Typescript занимает в 2-3 раза больше времени, чем раньше, т.к. теперь нельзя просто «по-быстрому набросать». Но однажды, перешагнув на «светлую сторону статической типизации», я ощутил всю мощь типов и то, как они позволяют в конечном итоге ускорить процесс разработки, что не менее важно, отладки кода (пожалуй, в те же самые 2-3 раза), а так же облегчить его дальнейшую поддержку.

P.S. Не забудьте поставить звезду этому модулю. :)

Благодарность
В заключение хочу поблагодарить мою любимую жену за терпение, котейку за приятное урчание рядом на столе, соседей за тишину и, конечно же, вас за внимание!
Источник: https://habr.com/ru/post/459050/


Интересные статьи

Интересные статьи

Маркетплейс – это сервис от 1С-Битрикс, который позволяет разработчикам делиться своими решениями с широкой аудиторией, состоящей из клиентов и других разработчиков.
Привет! Меня зовут Юрий Влад, я Android-разработчик в компании Badoo и занимаюсь внедрением Dynamic Features в наши проекты. Dynamic Delivery — технология, позволяющая устанавливать и удалят...
Vuex предоставляет удобные инструменты для работы с данными, но некоторые разработчики используют их не всегда по назначению, либо создают избыточные конструкции там, где можно было написать боле...
На сегодняшний день у сервиса «Битрикс24» нет сотен гигабит трафика, нет огромного парка серверов (хотя и существующих, конечно, немало). Но для многих клиентов он является основным инструментом ...
Один из самых острых вопросов при разработке на Битрикс - это миграции базы данных. Какие же способы облегчить эту задачу есть на данный момент?