VueJS: Module
Giải phóng thời gian, khai phóng năng lực
Do sử dụng một cây trạng thái duy nhất, tất cả trạng thái của ứng dụng của ta được chứa bên trong một đối tượng lớn. Tuy nhiên, khi ứng dụng của ta phát triển theo quy mô, store có thể thực sự cồng kềnh.
Để khắc phục điều đó, Vuex cho phép ta chia store của mình thành các mô-đun. Mỗi mô-đun có thể chứa state, mutations, actions, getters và thậm chí chứa cả các mô-đun khác:
const moduleA = { state: { ... }, mutations: { ... }, actions: { ... }, getters: { ... } } const moduleB = { state: { ... }, mutations: { ... }, actions: { ... } } const store = new Vuex.Store({ modules: { a: moduleA, b: moduleB } }) store.state.a // -> `moduleA`'s state store.state.b // -> `moduleB`'s state
Module state cục bộ
Bên trong các mutations và getters của mô-đun, đối số đầu tiên nhận được sẽ là state cục bộ của mô-đun.
const moduleA = { state: { count: 0 }, mutations: { increment (state) { // 'state' là state module cục bộ state.count++ } }, getters: { doubleCount (state) { return state.count * 2 } } }
Tương tự, bên trong các actions của mô-đun, context.state
sẽ hiển thị state cục bộ và state root sẽ được hiển thị dưới dạng context.rootState
:
const moduleA = { // ... actions: { incrementIfOddOnRootSum ({ state, commit, rootState }) { if ((state.count + rootState.count) % 2 === 1) { commit('increment') } } } }
Ngoài ra, bên trong getters
của module, state root
sẽ được hiển thị ở đối số thứ 3:
const moduleA = { // ... getters: { sumWithRootCount (state, getters, rootState) { return state.count + rootState.count } } }
Namespacing
Theo mặc định thì actions, mutations và getters bên trong mô-đun vẫn được đăng ký theo không gian tên chung - điều này cho phép nhiều mô-đun phản ứng với cùng một loại mutations/actions.
Nếu bạn muốn mô-đun của mình được tự chứa hoặc sử dụng lại nhiều hơn, bạn có thể đánh dấu mô-đun là không gian tên namespaced: true
. Khi module được đăng ký, tất cả các getters, actions và mutations của nó sẽ tự động được đặt tên dựa trên đường dẫn mà module được đăng ký. Ví dụ:
const store = new Vuex.Store({ modules: { account: { namespaced: true, // module asset state: { ... }, // state của module hoàn toàn được lồng và không bị ảnh hưởng bởi tùy chọn namespace getters: { isAdmin () { ... } // -> getters['account/isAdmin'] }, actions: { login () { ... } // -> dispatch('account/login') }, mutations: { login () { ... } // -> commit('account/login') }, // module lồng modules: { // inherits the namespace from parent module myPage: { state: { ... }, getters: { profile () { ... } // -> getters['account/profile'] } }, // further nest the namespace posts: { namespaced: true, state: { ... }, getters: { popular () { ... } // -> getters['account/posts/popular'] } } } } } })
getters và actions namespace sẽ được local hóa getters
, dispatch
và commit
. Nói cách khác, bạn có thể sử dụng các phần tử mô-đun mà không cần viết tiền tố trong cùng một mô-đun. Chuyển đổi giữa các không gian tên không ảnh hưởng đến mã bên trong mô-đun.
#Truy cập nội dung global trong các mô-đun không gian tên
Nếu bạn muốn sử dụng states global và getters, rootState
và rootGetters
được truyền như các đối số thứ 3 và thứ 4 cho các hàm getter, và cũng được hiển thị như các thuộc tính trên đối tượng context
được truyền cho các hàm action.
Để gửi các actions hoặc thực hiện các mutations trong không gian tên chung, hãy chuyển { root: true }
làm đối số thứ 3 đến dispatch
và commit
.
modules: { foo: { namespaced: true, getters: { // `getters` được cục bộ hóa cho các getters của module này // bạn có thể sử dụng rootGetters qua đối số thứ 4 của getters someGetter (state, getters, rootState, rootGetters) { getters.someOtherGetter // -> 'foo/someOtherGetter' rootGetters.someOtherGetter // -> 'someOtherGetter' }, someOtherGetter: state => { ... } }, actions: { // dispatch và commit cũng được cục bộ hóa cho module này // chúng sẽ chấp nhận tùy chọn `root` cho root dispatch/commit someAction ({ dispatch, commit, getters, rootGetters }) { getters.someGetter // -> 'foo/someGetter' rootGetters.someGetter // -> 'someGetter' dispatch('someOtherAction') // -> 'foo/someOtherAction' dispatch('someOtherAction', null, { root: true }) // -> 'someOtherAction' commit('someMutation') // -> 'foo/someMutation' commit('someMutation', null, { root: true }) // -> 'someMutation' }, someOtherAction (ctx, payload) { ... } } } }
#Đăng ký global action trong Mô-đun không gian tên
Nếu bạn muốn đăng ký các global actions trong các mô-đun không gian tên, bạn có thể đánh dấu nó bằng root: true
và đặt định nghĩa bộ xử lý action trong actions. Ví dụ:
{ actions: { someOtherAction ({dispatch}) { dispatch('someAction') } }, modules: { foo: { namespaced: true, actions: { someAction: { root: true, handler (namespacedContext, payload) { ... } // -> 'someAction' } } } } }
#Ràng buộc Helper với không gian tên
Khi gắn một module namespaced với các component với các helper mapState
, mapGetters
, mapActions
và mapMutations
, nó có thể nhận được một chút chi tiết:
computed: { ...mapState({ a: state => state.some.nested.module.a, b: state => state.some.nested.module.b }) }, methods: { ...mapActions([ 'some/nested/module/foo', // -> this['some/nested/module/foo']() 'some/nested/module/bar' // -> this['some/nested/module/bar']() ]) }
Trong những trường hợp như vậy, bạn có thể truyền chuỗi không gian tên mô-đun làm đối số đầu tiên cho helper để tất cả các ràng buộc được thực hiện bằng cách sử dụng mô-đun đó làm ngữ cảnh. Đoạn code trên có thể được đơn giản hóa thành:
computed: { ...mapState('some/nested/module', { a: state => state.a, b: state => state.b }) }, methods: { ...mapActions('some/nested/module', [ 'foo', // -> this.foo() 'bar' // -> this.bar() ]) }
Hơn nữa, bạn có thể tạo helper không gian tên bằng cách sử dụng createNamespacedHelpers
. Nó trả về một đối tượng có các helper ràng buộc component mới được ràng buộc với giá trị không gian tên đã cho:
import { createNamespacedHelpers } from 'vuex' const { mapState, mapActions } = createNamespacedHelpers('some/nested/module') export default { computed: { // hãy để ý `some/nested/module` ...mapState({ a: state => state.a, b: state => state.b }) }, methods: { // hãy để ý `some/nested/module` ...mapActions([ 'foo', 'bar' ]) } }
Caveat dành cho nhà phát triển plugin
Bạn có thể quan tâm đến việc đặt tên không thể đoán trước cho các mô-đun của bạn khi bạn tạo một plugin cung cấp các mô-đun và cho phép người dùng thêm chúng vào store Vuex. Mô-đun của bạn cũng sẽ được đặt tên nếu người dùng plugin thêm mô-đun của bạn trong mô-đun không gian tên. Để điều chỉnh tình huống này, bạn có thể cần nhận được một giá trị không gian tên thông qua tùy chọn plugin của bạn:
// lấy giá trị namespace qua tùy chọn plugin // và trả về function plugin Vuex export function createPlugin (options = {}) { return function (store) { // và namespace tới các type của module plugin const namespace = options.namespace || '' store.dispatch(namespace + 'pluginAction') } }
Đăng ký mô-đun động
Bạn có thể đăng ký một mô-đun sau khi store đã được tạo bằng phương thức store.registerModule
:
// đăng ký module `myModule` store.registerModule('myModule', { // ... }) // đăng ký module lồng `nested/myModule` store.registerModule(['nested', 'myModule'], { // ... })
state của mô-đun sẽ được hiển thị dưới dạng store.state.myModule
và store.state.nested.myModule
.
Đăng ký mô-đun động làm cho nó có thể cho các plugin Vue khác cũng tận dụng Vuex cho quản lý state bằng cách gắn một mô-đun vào kho ứng dụng. Ví dụ: thư viện vuex-router-sync tích hợp router vue với vuex bằng cách quản lý route state của ứng dụng trong mô-đun được đính kèm động.
Bạn cũng có thể loại bỏ một mô-đun đăng ký động bằng store.unregisterModule(moduleName)
. Lưu ý rằng bạn không thể loại bỏ các mô-đun tĩnh (khai báo tại store) bằng cách thức này.
Có thể bạn muốn giữ state trước đó khi đăng ký một mô-đun mới, chẳng hạn như bảo toàn state từ ứng dụng Máy chủ được hiển thị. Bạn có thể đạt được điều này với tùy chọn preserveState
:store.registerModule('a', module, { preserveState: true })
Mô-đun tái sử dụng
Đôi khi, chúng ta có thể cần phải tạo nhiều phiên bản của một mô-đun, ví dụ:
- Tạo nhiều store sử dụng cùng một mô-đun (ví dụ: Để tránh các trình đơn trạng thái trong SSR khi tùy chọn
runInNewContext
làfalse
hoặc'once'
); - Đăng ký cùng một mô-đun nhiều lần trong cùng một store.
Nếu ta sử dụng một đối tượng đơn giản để khai báo state của mô-đun, thì đối tượng state đó sẽ được chia sẻ bằng tham chiếu và gây nhiễu loạn state store/mô-đun khi nó được mutation.
Đây thực sự là vấn đề với component data
bên trong Vue. Vì vậy, giải pháp cũng giống nhau - sử dụng một hàm để khai báo state mô-đun (được hỗ trợ trong 2.3.0+):
const MyReusableModule = { state () { return { foo: 'bar' } }, // mutations, actions, getters... }
Giải phóng thời gian, khai phóng năng lực