Module de frappe puissant Vuex

Le motif de la rédaction de cet article était un autre article sur la dactylographie de Vue et, par conséquent, Vuex . À ma grande surprise, je n'ai pas trouvé de mention d'un module là-bas, qui, à mon avis, est le meilleur de Vuex en son genre. La recherche de Habr, et en effet du Runet (en fait, et dans les sources anglaises il n'est pas facile de trouver immédiatement des références), hélas, n'a donné aucun résultat. Cet article n'est pas une analyse détaillée et un manuel de plusieurs pages sur l'utilisation et la configuration, mais plutôt un moyen de partager avec vous, cher Vue-ninja, un outil qui fait parfaitement son travail.

module-vuex-smart


Qui n'a pas le temps du tout: Github .

Le principal objectif du module, comme vous l'avez peut-être deviné, est la couverture complète du stockage Vuex avec des types. En interne et directement dans les composants eux-mêmes. Le module est écrit par le contributeur principal ( @ktsn ) des bibliothèques Vuex et vue-class-component .

De l'eau


Pour l'admettre, mon chemin dans Typescript n'a commencé que récemment, y compris et avec des choses comme les décorateurs, donc je ne peux pas comparer cette bibliothèque avec d'autres analogues. Mes tentatives de configuration et d'utilisation d'autres outils (par exemple, décorateurs de module vuex ) m'ont conduit à divers problèmes, qui au final ne m'ont pas permis de réaliser ce dont j'avais besoin (ou je ne savais tout simplement pas comment les cuisiner, comme on dit). J'ai eu beaucoup de chance avec vuex-smart-module - la bibliothèque est apparue au moment même où je traduisais le projet (et le référentiel) en Typescript. Maintenant, tout fonctionne bien et le code est agréable à l'œil.

Des exemples


La bibliothèque, à mon avis, a une bonne documentation qui couvre tous les cas possibles que vous rencontrerez (et sinon, dans les tests, vous trouverez tout le reste, non trivial). Cependant, afin de diluer au moins l'article avec du code, je donnerai des exemples de base de connexion et d'utilisation, quelques exemples de «vie», ainsi que la façon dont cela fonctionne en collaboration avec les décorateurs (il y a une nuance ici).

Création de module


Un module est créé à l'aide de classes. Cela peut sembler angoissant pour certains, mais croyez-moi, vous vous y habituez rapidement.

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

Connexion


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

Modules


La connexion des modules est similaire à la façon dont cela se produit dans Vuex standard. Ils doivent être spécifiés dans la propriété modules de RootStore:

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

Utiliser à l'intérieur d'un composant


Vous pouvez utiliser le stockage à la fois via la propriété globale this. $ Store et via le mappage, qui à bien des égards est similaire à celui de 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) } }) 


Dactylographie


Exemple de saisie de validation et de répartition:
 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 } ) } } 


Réceptions


Se connecter à l'aide de décorateurs ( 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) } } 

Utiliser un module à l'intérieur d'un module


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

Réinitialisation du coffre-fort


Parfois, il peut être nécessaire de réinitialiser le stockage aux valeurs par défaut, cela se fait tout simplement:

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

Finale


J'espère que vous étiez intéressé, ou du moins que vous avez découvert cette bibliothèque. Qui sait, peut-être en commençant par le prochain projet (ou peut-être en refactorisant les projets actuels juste au coin de la rue?) Vous, comme moi, allez commencer à utiliser vuex-smart-module (ou Typescript en général)? Personnellement, ma transition vers Typescript a été assez pénible (pendant 1,5 à 2 ans, j'ai tenté au moins de passer à cela 3-4 fois, mais à chaque fois j'ai rencontré des problèmes, des malentendus. J'ai souvent été hanté par le sentiment que le développement sur Typescript prend 2 à 3 fois plus de temps qu'auparavant, car maintenant vous ne pouvez plus simplement "esquisser rapidement". Mais une fois, en marchant du "côté positif de la frappe statique", j'ai ressenti la puissance des types et comment ils permettent finalement accélérer le processus de développement, qui est tout aussi important, en déboguant le code (peut-être dans le même 2- 3 fois), ainsi que de faciliter son soutien ultérieur.

PS N'oubliez pas de mettre une étoile sur ce module. :)

Gratitude
En conclusion, je tiens à remercier ma femme bien-aimée pour sa patience, un chat pour un agréable grondement près de la table, des voisins pour le silence et, bien sûr, pour votre attention!

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


All Articles