Divide the whole into parts and step by step
You can’t do it without modules, just like no one can build a pyramid in one step.
Because of the use of a single state tree, all the states of an application are grouped into one large object.
As the application becomes very complex, you will find that your Vuex module becomes a large module with thousands of lines.
To solve these problems, Vuex allows us to split a single store into modules.
Each module has its own state, mutation, action, getter, and even nested submodules (split in the same way)
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 status Store.state. b // -> moduleB statusCopy the code
-
Local state of a module
For mutation and getters inside a module, the first argument received is the module object it is in.
const moduleA = { state: () => ({ count: 0 }), mutations: Count++}}, getters: {doubleCount (state) {// same as the dropup ~return state.count * 2
}
}
}
Copy the code
The actions inside the module are slightly different, remember what I said about context? The reader is supposed to use it as if it were their own module object. It is not. It has context.rootState, which accesses the state of the parent node
const moduleA = {
actions: {
incrementIfOddOnRootSum ({ state, commit, rootState }) {
if ((state.count + rootState.count) % 2 === 1) {
commit('increment')}}}}Copy the code
The getter is exposed in the third argument
const moduleA = {
getters: {
sumWithRootCount (state, getters, rootState) {
return state.count + rootState.count
}
}
}
Copy the code
-
Namespace namespaced
By default, actions, mutations, and getters inside a module are registered in the global namespace — enabling multiple modules to respond to the same mutation or action.
You can make it a namespaced module by adding Namespaced: True (it almost always does).
When a module is registered, all its getters, actions, and mutations are automatically named according to the path the module was registered with. Such as:
Const store = new vuex. store ({account: {namespaced: const store = new vuex. store ({account: {namespaced:trueState: () => ({... }), // state is already nested, and 'namespaced' doesn't affect it.isAdmin() {... } // -> getters['account/isAdmin'}, actions: {login() {... } // -> dispatch('account/login')
},
mutations: {
login() {... } // -> commit('account/login'// Bungled myPage: {state: () => ({... }), getters: {profile() {... } // -> getters['account/profile'// namaspaced posts: {namespaced: // namaspaced posts: {namespaced:true,
state: () => ({ ... }),
getters: {
popular() {... } // -> getters['account/posts/popular'] // Has its own hierarchy}}}}}})Copy the code
-
How does a namespace access other namespaces or global Spaces?
We can see that when the namespace is enabled, the nested module is like a “child”, so there must be a way for it to access the parent module. Otherwise, practicality is almost useless.
Previously, the section on the local state of a module explained a little bit about how to access it, but now to explain the following in more detail.
modules: {
foo: {
namespaced: true// Remember to enable getters: {// In the getter of this module, 'getters' is localized // You can see that the third argument is rootState, RootGetters someGetter (state, getters, rootState, rootGetters) {getters.someothergetter // ->'foo/someOtherGetter'
rootGetters.someOtherGetter // -> 'someOtherGetter'}, someOtherGetter: state => { ... } }, actions: {// In this module, // They can accept the 'root' attribute to access the root dispatch or commit someAction ({dispatch, commit, getters, rootGetters }) { getters.someGetter // ->'foo/someGetter'
rootGetters.someGetter // -> 'someGetter'
dispatch('someOtherAction') / / - >'foo/someOtherAction'
dispatch('someOtherAction', null, { root: true}) / / - >'someOtherAction'As you can see from above, it already triggers the dispatch from the parent module, which is easy enough. // The parent module triggers the child module in the same way, so the communication between sibling modules is implemented. dispatch('someOtherAction/otherModule', null, { root: true}) / / - >'someOtherAction'
commit('someMutation') / / - >'foo/someMutation'
commit('someMutation', null, { root: true}) / / - >'someMutation'}, someOtherAction (ctx, payload) { ... }}}}Copy the code
-
How do I register global actions in a local module?
To register a global action in a namespaced module, add root: true and put the action definition in a function handler. Such as:
{
actions: {
someOtherAction ({dispatch}) {
dispatch('someAction')
}
},
modules: {
foo: {
namespaced: true, actions: {someAction: {// what was originally a function is now an object root:true, // Must nottrueTo register the global handler (namespacedContext, payload) {... } / / - >'someAction'// The function must have the handler name. , and then the function is written the same as a normal function. } } } } }Copy the code
-
Simplified auxiliary function map… The writing of
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']()])} // Rewrite to computed: {... mapState('some/nested/module', { a: state => state.a, b: state => state.b }) }, methods: { ... mapActions('some/nested/module'['foo', // -> this.foo()
'bar' // -> this.bar()
])
}
Copy the code
There is still a little bit of content that has nothing to do with entry, so it is not necessary to add reading pressure and be interested in moving to the official website.