Skip to content

Commit ec293df

Browse files
ktsnyyx990803
authored andcommitted
Allow to register module getters dynamically (#253)
* put together initialization code of vm into initStoreVM function * add getters dynamically by `module` method * fix incorrect init of getters * rename _getters -> _wrappedGetters * fix wrong comment
1 parent a8bca40 commit ec293df

File tree

2 files changed

+76
-73
lines changed

2 files changed

+76
-73
lines changed

src/index.js

Lines changed: 70 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ class Store {
1111

1212
const {
1313
state = {},
14-
modules = {},
1514
plugins = [],
1615
strict = false
1716
} = options
@@ -21,6 +20,7 @@ class Store {
2120
this._committing = false
2221
this._actions = Object.create(null)
2322
this._mutations = Object.create(null)
23+
this._wrappedGetters = Object.create(null)
2424
this._subscribers = []
2525
this._pendingActions = []
2626

@@ -34,16 +34,17 @@ class Store {
3434
return commit.call(store, type, payload)
3535
}
3636

37-
// init state and getters
38-
const getters = extractModuleGetters(options.getters, modules)
39-
initStoreState(this, state, getters)
37+
// strict mode
38+
this.strict = strict
39+
40+
// init internal vm with root state
41+
// other options and sub modules will be
42+
// initialized in this.module method
43+
initStoreVM(this, state, {})
4044

4145
// apply root module
4246
this.module([], options)
4347

44-
// strict mode
45-
if (strict) enableStrictMode(this)
46-
4748
// apply plugins
4849
plugins.concat(devtoolPlugin).forEach(plugin => plugin(this))
4950
}
@@ -67,39 +68,10 @@ class Store {
6768
if (typeof path === 'string') path = [path]
6869
assert(Array.isArray(path), `module path must be a string or an Array.`)
6970

70-
const isRoot = !path.length
71-
const {
72-
state,
73-
actions,
74-
mutations,
75-
modules
76-
} = module
77-
78-
// set state
79-
if (!isRoot && !hot) {
80-
const parentState = getNestedState(this.state, path.slice(0, -1))
81-
if (!parentState) debugger
82-
const moduleName = path[path.length - 1]
83-
Vue.set(parentState, moduleName, state || {})
84-
}
85-
86-
if (mutations) {
87-
Object.keys(mutations).forEach(key => {
88-
this.mutation(key, mutations[key], path)
89-
})
90-
}
71+
initModule(this, path, module, hot)
9172

92-
if (actions) {
93-
Object.keys(actions).forEach(key => {
94-
this.action(key, actions[key], path)
95-
})
96-
}
73+
initStoreVM(this, this.state, this._wrappedGetters)
9774

98-
if (modules) {
99-
Object.keys(modules).forEach(key => {
100-
this.module(path.concat(key), modules[key], hot)
101-
})
102-
}
10375
this._committing = false
10476
}
10577

@@ -203,43 +175,33 @@ class Store {
203175
hotUpdate (newOptions) {
204176
this._actions = Object.create(null)
205177
this._mutations = Object.create(null)
178+
this._wrappedGetters = Object.create(null)
206179
const options = this._options
207180
if (newOptions.actions) {
208181
options.actions = newOptions.actions
209182
}
210183
if (newOptions.mutations) {
211184
options.mutations = newOptions.mutations
212185
}
186+
if (newOptions.getters) {
187+
options.getters = newOptions.getters
188+
}
213189
if (newOptions.modules) {
214190
for (const key in newOptions.modules) {
215191
options.modules[key] = newOptions.modules[key]
216192
}
217193
}
218194
this.module([], options, true)
219-
220-
// update getters
221-
const getters = extractModuleGetters(newOptions.getters, newOptions.modules)
222-
if (Object.keys(getters).length) {
223-
const oldVm = this._vm
224-
initStoreState(this, this.state, getters)
225-
if (this.strict) {
226-
enableStrictMode(this)
227-
}
228-
// dispatch changes in all subscribed watchers
229-
// to force getter re-evaluation.
230-
this._committing = true
231-
oldVm.state = null
232-
this._committing = false
233-
Vue.nextTick(() => oldVm.$destroy())
234-
}
235195
}
236196
}
237197

238198
function assert (condition, msg) {
239199
if (!condition) throw new Error(`[vuex] ${msg}`)
240200
}
241201

242-
function initStoreState (store, state, getters) {
202+
function initStoreVM (store, state, getters) {
203+
const oldVm = store._vm
204+
243205
// bind getters
244206
store.getters = {}
245207
const computed = {}
@@ -262,30 +224,67 @@ function initStoreState (store, state, getters) {
262224
computed
263225
})
264226
Vue.config.silent = silent
227+
228+
// enable strict mode for new vm
229+
if (store.strict) {
230+
enableStrictMode(store)
231+
}
232+
233+
if (oldVm) {
234+
// dispatch changes in all subscribed watchers
235+
// to force getter re-evaluation.
236+
store._committing = true
237+
oldVm.state = null
238+
store._committing = false
239+
Vue.nextTick(() => oldVm.$destroy())
240+
}
265241
}
266242

267-
function extractModuleGetters (getters = {}, modules = {}, path = []) {
268-
if (!path.length) {
269-
wrapGetters(getters, getters, path, true)
243+
function initModule (store, path, module, hot) {
244+
const isRoot = !path.length
245+
const {
246+
state,
247+
actions,
248+
mutations,
249+
getters,
250+
modules
251+
} = module
252+
253+
// set state
254+
if (!isRoot && !hot) {
255+
const parentState = getNestedState(store.state, path.slice(0, -1))
256+
if (!parentState) debugger
257+
const moduleName = path[path.length - 1]
258+
Vue.set(parentState, moduleName, state || {})
270259
}
271-
if (!modules) {
272-
return getters
260+
261+
if (mutations) {
262+
Object.keys(mutations).forEach(key => {
263+
store.mutation(key, mutations[key], path)
264+
})
265+
}
266+
267+
if (actions) {
268+
Object.keys(actions).forEach(key => {
269+
store.action(key, actions[key], path)
270+
})
271+
}
272+
273+
if (getters) {
274+
wrapGetters(store._wrappedGetters, getters, path)
275+
}
276+
277+
if (modules) {
278+
Object.keys(modules).forEach(key => {
279+
initModule(store, path.concat(key), modules[key], hot)
280+
})
273281
}
274-
Object.keys(modules).forEach(key => {
275-
const module = modules[key]
276-
const modulePath = path.concat(key)
277-
if (module.getters) {
278-
wrapGetters(getters, module.getters, modulePath)
279-
}
280-
extractModuleGetters(getters, module.modules, modulePath)
281-
})
282-
return getters
283282
}
284283

285-
function wrapGetters (getters, moduleGetters, modulePath, force) {
284+
function wrapGetters (getters, moduleGetters, modulePath) {
286285
Object.keys(moduleGetters).forEach(getterKey => {
287286
const rawGetter = moduleGetters[getterKey]
288-
if (getters[getterKey] && !force) {
287+
if (getters[getterKey]) {
289288
console.error(`[vuex] duplicate getter key: ${getterKey}`)
290289
return
291290
}

test/unit/test.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,12 +208,16 @@ describe('Vuex', () => {
208208
expect(() => {
209209
store.module('hi', {
210210
state: { a: 1 },
211-
mutations: { inc: state => state.a++ }
211+
mutations: { inc: state => state.a++ },
212+
actions: { inc: ({ commit }) => commit('inc') },
213+
getters: { a: state => state.a }
212214
})
213215
}).not.to.throw()
214216
expect(store.state.hi.a).to.equal(1)
215-
store.commit('inc')
217+
expect(store.getters.a).to.equal(1)
218+
store.dispatch('inc')
216219
expect(store.state.hi.a).to.equal(2)
220+
expect(store.getters.a).to.equal(2)
217221
})
218222

219223
it('store injection', () => {

0 commit comments

Comments
 (0)