# 数据获取
Vuex 最终存储的数据是在 state 上的,我们之前分析过在 store.state 存储的是 root state,那么对于模块上的 state,假设我们有 2 个嵌套的 modules,它们的 key 分别为 a 和 b,我们可以通过 store.state.a.b.xxx 的方式去获取。它的实现是在发生在 installModule 的时候:
function installModule (store, rootState, path, module, hot) { const isRoot = !path.length // ... // set state if (!isRoot && !hot) { const parentState = getNestedState(rootState, path.slice(0, -1)) const moduleName = path[path.length - 1] store._withCommit(() => { Vue.set(parentState, moduleName, module.state) }) } // ... }成功
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
在递归执行 installModule 的过程中,就完成了整个 state 的建设,这样我们就可以通过 module 名的 path 去访问到一个深层 module 的 state。
有些时候,我们获取的数据不仅仅是一个 state,而是由多个 state 计算而来,Vuex 提供了 getters,允许我们定义一个 getter 函数,如下:
getters: { total (state, getters, localState, localGetters) { // 可访问全局 state 和 getters,以及如果是在 modules 下面,可以访问到局部 state 和 局部 getters return state.a + state.b } }成功
1
2
3
4
5
6
2
3
4
5
6
我们在 installModule 的过程中,递归执行了所有 getters 定义的注册,在之后的 resetStoreVM 过程中,执行了 store.getters 的初始化工作:
function installModule (store, rootState, path, module, hot) { // ... const namespace = store._modules.getNamespace(path) // ... const local = module.context = makeLocalContext(store, namespace, path) // ... module.forEachGetter((getter, key) => { const namespacedType = namespace + key registerGetter(store, namespacedType, getter, local) }) // ... } function registerGetter (store, type, rawGetter, local) { if (store._wrappedGetters[type]) { if (process.env.NODE_ENV !== 'production') { console.error(`[vuex] duplicate getter key: ${type}`) } return } store._wrappedGetters[type] = function wrappedGetter (store) { return rawGetter( local.state, // local state local.getters, // local getters store.state, // root state store.getters // root getters ) } } function resetStoreVM (store, state, hot) { // ... // bind store public getters store.getters = {} const wrappedGetters = store._wrappedGetters const computed = {} forEachValue(wrappedGetters, (fn, key) => { // use computed to leverage its lazy-caching mechanism computed[key] = () => fn(store) Object.defineProperty(store.getters, key, { get: () => store._vm[key], enumerable: true // for local getters }) }) // use a Vue instance to store the state tree // suppress warnings just in case the user has added // some funky global mixins // ... store._vm = new Vue({ data: { $$state: state }, computed }) // ... }成功
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
在 installModule 的过程中,为建立了每个模块的上下文环境,
因此当我们访问 store.getters.xxx 的时候,实际上就是执行了 rawGetter(local.state,...),rawGetter 就是我们定义的 getter 方法,这也就是为什么我们的 getter 函数支持这四个参数,并且除了全局的 state 和 getter 外,我们还可以访问到当前 module 下的 state 和 getter。