Poderoso módulo de digitação Vuex

O motivo para escrever este artigo foi outro artigo sobre a digitação do Vue e, consequentemente, do Vuex . Para minha surpresa, não encontrei menção a um módulo lá, que, na minha opinião, é o melhor do tipo da Vuex. A busca por Habr e, de fato, pelo Runet (de fato, e em fontes inglesas não é fácil encontrar imediatamente nenhuma referência), infelizmente, não produziu nenhum resultado. Este artigo não é uma análise detalhada e um manual de várias páginas sobre o uso e a configuração, mas uma maneira de compartilhar com você, caro Vue-ninja, uma ferramenta que faz seu trabalho perfeitamente.

vuex-smart-module


Quem não tem tempo: Github .

O principal objetivo do módulo, como você deve ter adivinhado, é a cobertura em formato completo do armazenamento Vuex por tipos. Internamente e diretamente nos próprios componentes. O módulo é escrito pelo colaborador principal ( @ktsn ) das bibliotecas Vuex e vue-class-component .

Agua


Para admitir, meu caminho no Typescript começou apenas recentemente, incluindo e com coisas como decoradores, então não posso comparar esta biblioteca com outros análogos. Minhas tentativas de configurar e usar outras ferramentas (por exemplo, vuex-module-decorators ) me levaram a vários problemas, que de alguma forma não me permitiram perceber o que eu precisava (ou simplesmente não sabia como cozinhá-los, como eles dizem). Tive muita sorte com o vuex-smart-module - a biblioteca apareceu no momento em que eu estava traduzindo o projeto (e o repositório) para o Typecript. Agora tudo funciona bem, e o código é agradável aos olhos.

Exemplos


A biblioteca, na minha opinião, possui uma boa documentação que cobre todos os casos possíveis que você encontrará (e, caso contrário, nos testes você poderá encontrar todo o resto, não trivial). No entanto, para pelo menos de alguma forma diluir o artigo com código, darei exemplos básicos de conexão e uso, alguns exemplos de “vida”, bem como como ele funciona em conjunto com os decoradores (há uma nuance).

Criação de módulo


Um módulo é criado usando classes. Para alguns, isso pode parecer extraordinariamente assustador, mas acredite, você se acostuma rapidamente.

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 }) 

Ligação


/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' } ) 

Módulos


A conexão de módulos é semelhante à como acontece no Vuex comum. Eles precisam ser especificados na propriedade de módulos do RootStore:

 import FooStore from './modules/foo' /* … */ export default new Module({ state: RootState, getters: RootGetters, mutations: RootMutations, actions: RootActions, modules: { FooStore } }) 

Use dentro de um componente


Você pode usar o armazenamento através da propriedade global this. $ Store e através do mapeamento, que de várias maneiras é semelhante ao do 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) } }) 


Digitação


Exemplo de digitação commit e dispatch:
 import { categories } from '@/api' export type Category { attributes: { hasPrice: boolean; icon: string lvl: number name: string slug: string }; id: number } export interface IParams { city_id: number } class AppState { categories: Category[] = [] } /* ... */ class AppMutations extends Mutations<AppState> { setCategories(categories: Category[]) { this.state.categories = categories } } class AppActions extends Actions< AppState, AppGetters, AppMutations, AppActions > { async getCategories({params}: {params: IParams}): Promise<Category[]> { return categories.get({params}).then( ({ data }: { data: Category[] }) => { this.commit("setCategories", data) return data } ) } } 


Recepções


Conectar usando decoradores ( 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) } } 

Usando um módulo dentro de um módulo


/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! } } /* … */ 

Reset do cofre


Às vezes, pode ser necessário redefinir o armazenamento para os valores padrão, isso é feito de maneira simples:

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

Final


Espero que você tenha se interessado, ou pelo menos tenha descoberto esta biblioteca. Quem sabe, talvez a partir do próximo projeto (ou refatorando os atuais ao virar da esquina?) Você, como eu, começará a usar o vuex-smart-module (ou o Typcript em geral)? Pessoalmente, minha transição para o Typescript foi bastante dolorosa (por 1,5 a 2 anos, tentei alterná-lo de 3 a 4 vezes, pelo menos, mas cada vez que encontrava alguns problemas, mal-entendidos, eu era frequentemente assombrado pela sensação de que o desenvolvimento no Typescript leva 2-3 vezes mais do que antes, porque agora você não pode "esboçar rapidamente". Mas, uma vez, entrando no "lado positivo da digitação estática", senti o poder dos tipos e como eles finalmente permitem acelerar o processo de desenvolvimento, que é igualmente importante, depurando o código (talvez no mesmo 3 vezes), além de facilitar seu apoio adicional.

PS Não se esqueça de colocar uma estrela neste módulo. :)

Gratidão
Concluindo, quero agradecer a minha amada esposa por sua paciência, um gato por um agradável ronco perto da mesa, vizinhos por silêncio e, é claro, por sua atenção!

Source: https://habr.com/ru/post/pt459050/


All Articles