11import devtoolPlugin from './plugins/devtool'
2- import strictPlugin from './plugins/strict'
32import applyMixin from './mixin'
3+ import { mapGetters , mapActions } from './helpers'
44
55let Vue // bind on install
66
@@ -38,24 +38,18 @@ class Store {
3838 this . call = bind ( this . call , this )
3939 this . dispatch = bind ( this . dispatch , this )
4040
41- // use a Vue instance to store the state tree
42- // suppress warnings just in case the user has added
43- // some funky global mixins
44- const silent = Vue . config . silent
45- Vue . config . silent = true
46- this . _vm = new Vue ( { data : { state } } )
47- Vue . config . silent = silent
41+ // init state and getters
42+ extractModuleGetters ( getters , modules )
43+ initStoreState ( this , state , getters )
4844
4945 // apply root module
5046 this . module ( [ ] , options )
5147
48+ // strict mode
49+ if ( strict ) enableStrictMode ( this )
50+
5251 // apply plugins
53- plugins = plugins . concat (
54- strict
55- ? [ devtoolPlugin , strictPlugin ]
56- : [ devtoolPlugin ]
57- )
58- plugins . forEach ( plugin => plugin ( this ) )
52+ plugins . concat ( devtoolPlugin ) . forEach ( plugin => plugin ( this ) )
5953 }
6054
6155 get state ( ) {
@@ -88,7 +82,7 @@ class Store {
8882
8983 // set state
9084 if ( ! isRoot && ! hot ) {
91- const parentState = get ( this . state , path . slice ( - 1 ) )
85+ const parentState = getNestedState ( this . state , path . slice ( - 1 ) )
9286 const moduleName = path [ path . length - 1 ]
9387 Vue . set ( parentState , moduleName , state || { } )
9488 }
@@ -117,7 +111,7 @@ class Store {
117111 entry . push ( payload => {
118112 handler ( getNestedState ( this . state , path ) , payload )
119113 } )
120- } ,
114+ }
121115
122116 action ( type , handler , path = [ ] ) {
123117 const entry = this . _actions [ type ] || ( this . _actions [ type ] = [ ] )
@@ -153,7 +147,7 @@ class Store {
153147 this . _dispatching = true
154148 entry . forEach ( handler => handler ( payload ) )
155149 this . _dispatching = false
156- this . _subscribers . forEach ( sub => sub ( mutation , state ) )
150+ this . _subscribers . forEach ( sub => sub ( mutation , this . state ) )
157151 }
158152
159153 call ( type , payload , cb ) {
@@ -177,14 +171,14 @@ class Store {
177171 subs . push ( fn )
178172 }
179173 return ( ) => {
180- let i = subs . indexOf ( fn )
174+ const i = subs . indexOf ( fn )
181175 if ( i > - 1 ) {
182176 subs . splice ( i , 1 )
183177 }
184178 }
185179 }
186180
187- update ( newOptions ) {
181+ hotUpdate ( newOptions ) {
188182 this . _actions = Object . create ( null )
189183 this . _mutations = Object . create ( null )
190184 const options = this . _options
@@ -200,11 +194,82 @@ class Store {
200194 }
201195 }
202196 this . module ( [ ] , options , true )
197+
198+ // update getters
199+ const getters = extractModuleGetters ( newOptions . getters || { } , newOptions . modules )
200+ if ( Object . keys ( getters ) . length ) {
201+ const oldVm = this . _vm
202+ initStoreState ( this , this . state , getters )
203+ if ( this . strict ) {
204+ enableStrictMode ( this )
205+ }
206+ // trigger changes in all subscribed watchers
207+ // to force getter re-evaluation.
208+ this . _dispatching = true
209+ oldVm . state = null
210+ this . _dispatching = false
211+ Vue . nextTick ( ( ) => oldVm . $destroy ( ) )
212+ }
203213 }
204214}
205215
216+ function initStoreState ( store , state , getters ) {
217+ // bind getters
218+ store . getters = { }
219+ const computed = { }
220+ Object . keys ( getters ) . forEach ( key => {
221+ const fn = getters [ key ]
222+ // use computed to leverage its lazy-caching mechanism
223+ computed [ key ] = ( ) => fn ( store . _vm . state )
224+ Object . defineProperty ( store . getters , key , {
225+ get : ( ) => store . _vm [ key ]
226+ } )
227+ } )
228+
229+ // use a Vue instance to store the state tree
230+ // suppress warnings just in case the user has added
231+ // some funky global mixins
232+ const silent = Vue . config . silent
233+ Vue . config . silent = true
234+ store . _vm = new Vue ( {
235+ data : { state } ,
236+ computed
237+ } )
238+ Vue . config . silent = silent
239+ }
240+
241+ function extractModuleGetters ( getters , modules , path = [ ] ) {
242+ if ( ! modules ) return
243+ Object . keys ( modules ) . forEach ( key => {
244+ const module = modules [ key ]
245+ if ( module . getters ) {
246+ Object . keys ( module . getters ) . forEach ( getterKey => {
247+ const rawGetter = module . getters [ getterKey ]
248+ if ( getters [ getterKey ] ) {
249+ console . warn ( `[vuex] duplicate getter key: ${ getterKey } ` )
250+ return
251+ }
252+ getters [ getterKey ] = state => rawGetter ( getNestedState ( state , path ) )
253+ } )
254+ }
255+ extractModuleGetters ( getters , module . modules , path . concat ( key ) )
256+ } )
257+ }
258+
259+ function enableStrictMode ( store ) {
260+ store . _vm . watch ( 'state' , ( ) => {
261+ if ( ! store . _dispatching ) {
262+ throw new Error (
263+ '[vuex] Do not mutate vuex store state outside mutation handlers.'
264+ )
265+ }
266+ } , { deep : true , sync : true } )
267+ }
268+
206269function bind ( fn , ctx ) {
207- return ( ) => fn . apply ( ctx , arguments )
270+ return function ( ) {
271+ return fn . apply ( ctx , arguments )
272+ }
208273}
209274
210275function isObject ( obj ) {
@@ -237,5 +302,7 @@ if (typeof window !== 'undefined' && window.Vue) {
237302
238303export default {
239304 Store,
240- install
305+ install,
306+ mapGetters,
307+ mapActions
241308}
0 commit comments