Seperti banyak pengembang, saya menulis proyek saya sendiri yang
Penyangkalan
Persyaratan dasar untuk sebuah toko:
- Jenis skrip harus berfungsi dalam modul
- Modul harus mudah digunakan dalam komponen, tipe untuk status, tindakan, mutasi, dan pengambil harus berfungsi
- Jangan membuat api baru untuk vuex, Anda harus memastikan bahwa jenis skrip bekerja dengan modul vuex sehingga Anda tidak perlu menulis ulang seluruh aplikasi sekaligus
- Memanggil mutasi dan tindakan harus sesederhana dan sesederhana mungkin
- Paket harus sekecil mungkin
- Saya tidak ingin menyimpan konstanta dengan nama mutasi dan tindakan
- Ini harus bekerja (Dan bagaimana tanpa itu)
Tidak mungkin proyek yang matang seperti vuex tidak memiliki dukungan skrip jenis normal. Nah, kami membuka
vuex-smart-module
github.com/ktsn/vuex-smart-module
Bagus, sangat bagus. Semuanya dengan saya, tetapi secara pribadi saya tidak suka fakta bahwa untuk tindakan, mutasi, status, getter, Anda perlu membuat kelas terpisah. Ini, tentu saja, adalah selera, tetapi ini saya dan proyek saya) Dan secara umum, masalah pengetikan belum sepenuhnya terselesaikan ( utas komentar dengan penjelasan mengapa ).
Vuex Typescript Support Usaha yang
vuex-module-decorators
Ini sepertinya cara sempurna untuk berteman dengan vuex dan ketikan. Sepertinya vue-property-decorator yang saya gunakan dalam pengembangan, Anda dapat bekerja dengan modul seperti pada kelas, secara umum, super, tapi ...
Tapi tidak ada warisan. Kelas modul tidak diwariskan dengan benar dan masalah ini telah lama menggantung pada masalah ini! Dan tanpa pewarisan, akan ada banyak duplikasi kode. Panekuk…
Marah
Maka itu tidak sama sekali, baik, atau ± sama - tidak ada solusi yang ideal. Ini adalah saat yang tepat ketika Anda berkata pada diri sendiri: Mengapa saya mulai menulis proyek di vue? Nah, Anda tahu bereaksi, nah, saya akan menulis di bereaksi, tidak akan ada masalah seperti itu! Pada pekerjaan utama, proyek ini tidak sesuai dan Anda perlu memutakhirkannya - tekan argumen. Apakah itu sepadan dengan saraf yang dihabiskan dan malam tanpa tidur? Duduklah seperti orang lain, tulis komponentiki, tidak, yang paling Anda butuhkan! Lempar vue ini! Tulis untuk bereaksi, tingkatkan versi, dan bayar lebih untuk itu!
Pada saat itu, saya siap untuk membenci vue tidak seperti yang lain, tetapi itu adalah emosi, dan kecerdasan masih di atas itu. Vue (menurut pendapat subjektif saya) memiliki banyak keunggulan dibandingkan bereaksi, tetapi tidak ada kesempurnaan, begitu juga pemenang di medan perang. Baik vue maupun react sama-sama bagus dalam caranya masing-masing, dan karena bagian penting dari proyek ini sudah ditulis dalam vue, akan sebodoh mungkin untuk beralih untuk bereaksi sekarang. Saya harus memutuskan apa yang harus saya lakukan dengan vuex.
Tawar
Nah, semuanya tidak berjalan dengan baik. Mungkin kemudian vuex-smart-module? Paket ini sepertinya bagus, ya, Anda harus membuat banyak kelas, tetapi berfungsi dengan baik. Atau mungkin dia bisa mencoba menulis tipe untuk mutasi dan tindakan dengan tangan dalam komponen dan menggunakan vuex murni? Di sana, vue3 dengan vuex4 sedang diproses, mungkin mereka lebih baik menggunakan skrip. Jadi mari kita coba vuex murni. Secara umum, ini tidak mempengaruhi pekerjaan proyek, masih berfungsi, tidak ada jenis, tetapi Anda bertahan. Dan tunggu sebentar)
Awalnya saya mulai melakukan ini, tetapi kodenya ternyata mengerikan ...
Depresi
Saya harus pindah. Tapi di mana tidak diketahui. Itu adalah langkah yang benar-benar putus asa. Saya memutuskan untuk membuat wadah negara dari awal . Kode itu disusun dalam beberapa jam. Dan ternyata hasilnya bagus. Jenis bekerja, status reaktif, dan bahkan warisan ada di sana. Namun segera penderitaan karena putus asa mulai surut, dan akal sehat mulai kembali. Secara keseluruhan, ide ini dibuang ke tempat sampah. Secara umum, ini adalah pola bus acara global. Dan itu hanya bagus untuk aplikasi kecil. Dan secara umum, menulis vuex Anda sendiri masih cukup berlebihan (setidaknya dalam situasi saya). Kemudian saya sudah menduga bahwa saya benar-benar kelelahan. Tapi sudah terlambat untuk mundur.
Tetapi jika ada yang tertarik, maka kodenya ada di sini: (Mungkin sia-sia menambahkan fragmen ini, tetapi jalurnya akan)
tidak terlihat gugup
const getModule = <T>(name:string, module:T) => {
const $$state = {}
const computed: Record<string, () => any> = {}
Object.keys(module).forEach(key => {
const descriptor = Object.getOwnPropertyDescriptor(
module,
key,
);
if (!descriptor) {
return
}
if (descriptor.get) {
const get = descriptor.get
computed[key] = () => {
return get.call(module)
}
} else if (typeof descriptor.value === 'function') {
// @ts-ignore
module[key] = module[key].bind(module)
} else {
// @ts-ignore
$$state[key] = module[key]
}
})
const _vm = new Vue({
data: {
$$state,
},
computed
})
Object.keys(computed).forEach((computedName) => {
var propDescription = Object.getOwnPropertyDescriptor(_vm, computedName);
if (!propDescription) {
throw new Error()
}
propDescription.enumerable = true
Object.defineProperty(module, computedName, {
get() { return _vm[computedName as keyof typeof _vm]},
// @ts-ignore
set(val) { _vm[computedName] = val}
})
})
Object.keys($$state).forEach(name => {
var propDescription = Object.getOwnPropertyDescriptor($$state,name);
if (!propDescription) {
throw new Error()
}
Object.defineProperty(module, name, propDescription)
})
return module
}
function createModule<
S extends {[key:string]: any},
M,
P extends Chain<M, S>
>(state:S, name:string, payload:P) {
Object.getOwnPropertyNames(payload).forEach(function(prop) {
const descriptor = Object.getOwnPropertyDescriptor(payload, prop)
if (!descriptor) {
throw new Error()
}
Object.defineProperty(
state,
prop,
descriptor,
);
});
const module = state as S & P
return {
module,
getModule() {
return getModule(name, module)
},
extends<E>(payload:Chain<E, typeof module>) {
return createModule(module, name, payload)
}
}
}
export default function SimpleStore<T>(name:string, payload:T) {
return createModule({}, name, payload)
}
type NonUndefined<A> = A extends undefined ? never : A;
type Chain<T extends {[key:string]: any}, THIS extends {[key:string]: any}> = {
[K in keyof T]: (
NonUndefined<T[K]> extends Function
? (this:THIS & T, ...p:Parameters<T[K]>) => ReturnType<T[K]>
: T[K]
)
}
Adopsi Kelahiran sepeda yang telah menyusul semua orang. vuexok
Untuk yang tidak sabar, kodenya ada di sini , dokumentasi singkatnya ada di sini .
Pada akhirnya, saya menulis perpustakaan kecil yang mencakup semua Wishlist dan bahkan sedikit lebih dari yang diminta. Tapi hal pertama yang pertama.
Modul vuexok paling sederhana terlihat seperti ini:
import { createModule } from 'vuexok'
import store from '@/store'
export const counterModule = createModule(store, 'counterModule', {
state: {
count: 0,
},
actions: {
async increment() {
counterModule.mutations.plus(1)
},
},
mutations: {
plus(state, payload:number) {
state.count += payload
},
setNumber(state, payload:number) {
state.count = payload
},
},
getters: {
x2(state) {
return state.count * 2
},
},
})
Yah, seperti vuex ... apa yang ada di baris 10?
counterModule.mutations.plus(1)
Wah! Apakah itu legal? Nah, dengan vuexok - ya, secara legal) Metode createModule mengembalikan objek yang persis mengulangi struktur objek modul vuex, hanya tanpa properti namespaced, dan kita bisa menggunakannya untuk memanggil mutasi dan tindakan atau untuk mendapatkan status dan getter, semua tipe dipertahankan. Dan dari tempat mana pun itu bisa diimpor.
Bagaimana dengan komponennya?
Dan dengan mereka semuanya baik-baik saja, karena sebenarnya itu vuex, maka, pada prinsipnya, tidak ada yang berubah, komit, pengiriman, mapState, dll. bekerja seperti sebelumnya.
Tapi sekarang Anda dapat membuat tipe dari modul berfungsi di komponen:
import Vue from 'vue'
import { counterModule } from '@/store/modules/counterModule'
import Component from 'vue-class-component'
@Component({
template: '<div>{{ count }}</div>'
})
export default class MyComponent extends Vue {
private get count() {
return counterModule.state.count // type number
}
}
Properti state dalam modul bersifat reaktif seperti di store.state, jadi untuk menggunakan status modul dalam komponen Vue, Anda hanya perlu mengembalikan sebagian status modul dalam properti yang dihitung. Hanya ada satu peringatan. Saya sengaja membuat status Readonly menjadi tipe, tidak baik mengubah status vuex jadi.
Memanggil tindakan dan mutasi mudah dipermalukan dan jenis parameter input juga disimpan
private async doSomething() {
counterModule.mutations.setNumber(10)
// this.$store.commit('counterModule/setNumber', 10)
await counterModule.actions.increment()
// await this.$store.dispatch('counterModule/increment')
}
Inilah keindahan yang luar biasa. Beberapa saat kemudian, saya juga perlu bereaksi terhadap perubahan jwt, yang juga disimpan di toko. Dan kemudian metode arloji muncul di modul. Pengamat modul bekerja dengan cara yang sama seperti store.watch. Satu-satunya perbedaan adalah bahwa status dan pengambil modul dilewatkan sebagai parameter fungsi pengambil.
const unwatch = jwtModule.watch(
(state) => state.jwt,
(jwt) => console.log(`New token: ${jwt}`),
{ immediate: true },
)
Jadi apa yang kami miliki:
- sisi yang diketik - ya
- jenis bekerja dalam komponen - ya
- api seperti di vuex dan segala sesuatu yang sebelumnya di vuex murni tidak rusak - adalah
- pekerjaan deklaratif dengan sisi - ya
- ukuran paket kecil (~ 400 byte gzip) - ya
- tidak perlu menyimpan nama-nama tindakan dan mutasi dalam konstanta - ada
- itu harus bekerja - adalah
Secara umum, aneh bahwa fitur luar biasa seperti itu tidak tersedia di vuex di luar kotak, sungguh luar biasa betapa nyamannya itu!
Adapun dukungan untuk vuex4 dan vue3 - Saya belum mengujinya, tetapi dilihat dari dokumennya, itu harus kompatibel.
Masalah yang disajikan dalam artikel ini juga terpecahkan:
Vuex - menyelesaikan perselisihan lama dengan metode baru
Vuex memecahkan enkapsulasi
Mimpi basah:
Akan sangat bagus untuk membuatnya sehingga mutasi dan tindakan lain tersedia dalam konteks tindakan.
Bagaimana melakukan ini dalam konteks tipe skrip - kontol tahu itu. Tetapi jika Anda bisa melakukan ini:
{
actions: {
one(injectee) {
injectee.actions.two()
},
two() {
console.log('tada!')
}
}
Bahwa kegembiraan saya tidak akan terbatas. Tapi hidup, seperti naskah, adalah hal yang keras.
Inilah petualangan dengan vuex dan ketikan. Yah, saya agak angkat bicara. Terima kasih atas perhatiannya.