index.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. import { createAction, mergeObjects, deepClone } from './util'
  2. import devtoolMiddleware from './middlewares/devtool'
  3. let Vue
  4. export default class Vuex {
  5. /**
  6. * @param {Object} options
  7. * - {Object} state
  8. * - {Object} actions
  9. * - {Object} mutations
  10. * - {Array} middlewares
  11. */
  12. constructor ({
  13. state = {},
  14. actions = {},
  15. mutations = {},
  16. middlewares = []
  17. } = {}) {
  18. // use a Vue instance to store the state tree
  19. this._vm = new Vue({
  20. data: state
  21. })
  22. this.actions = Object.create(null)
  23. this._setupActions(actions)
  24. this._setupMutations(mutations)
  25. this._setupMiddlewares(middlewares, state)
  26. }
  27. /**
  28. * Getter for the entire state tree.
  29. * Read only.
  30. *
  31. * @return {Object}
  32. */
  33. get state () {
  34. return this._vm._data
  35. }
  36. set state (v) {
  37. throw new Error('[vuex] Vuex root state is read only.')
  38. }
  39. /**
  40. * Dispatch an action.
  41. *
  42. * @param {String} type
  43. */
  44. dispatch (type, ...payload) {
  45. const mutation = this._mutations[type]
  46. const prevSnapshot = this._prevSnapshot
  47. const state = this.state
  48. let snapshot, clonedPayload
  49. if (mutation) {
  50. // apply the mutation
  51. if (Array.isArray(mutation)) {
  52. mutation.forEach(m => m(state, ...payload))
  53. } else {
  54. mutation(state, ...payload)
  55. }
  56. // invoke middlewares
  57. if (this._needSnapshots) {
  58. snapshot = this._prevSnapshot = deepClone(state)
  59. clonedPayload = deepClone(payload)
  60. }
  61. this._middlewares.forEach(m => {
  62. if (m.snapshot) {
  63. m.onMutation({ type, payload: clonedPayload }, snapshot, prevSnapshot)
  64. } else {
  65. m.onMutation({ type, payload }, state)
  66. }
  67. })
  68. } else {
  69. console.warn(`[vuex] Unknown mutation: ${ type }`)
  70. }
  71. }
  72. /**
  73. * Hot update actions and mutations.
  74. *
  75. * @param {Object} options
  76. * - {Object} [actions]
  77. * - {Object} [mutations]
  78. */
  79. hotUpdate ({ actions, mutations } = {}) {
  80. if (actions) {
  81. this._setupActions(actions, true)
  82. }
  83. if (mutations) {
  84. this._setupMutations(mutations)
  85. }
  86. }
  87. _setupActions (actions, hot) {
  88. // keep the real action functions in an internal object,
  89. // and expose the public object which are just wrapper
  90. // functions that point to the real ones. This is so that
  91. // the reals ones can be hot reloaded.
  92. this._actions = Object.create(null)
  93. actions = Array.isArray(actions)
  94. ? mergeObjects(actions)
  95. : actions
  96. Object.keys(actions).forEach(name => {
  97. this._actions[name] = createAction(actions[name], this)
  98. if (!this.actions[name]) {
  99. this.actions[name] = (...args) => this._actions[name](...args)
  100. }
  101. })
  102. // delete public actions that are no longer present
  103. // after a hot reload
  104. if (hot) {
  105. Object.keys(this.actions).forEach(name => {
  106. if (!actions[name]) {
  107. delete this.actions[name]
  108. }
  109. })
  110. }
  111. }
  112. _setupMutations (mutations) {
  113. this._mutations = Array.isArray(mutations)
  114. ? mergeObjects(mutations, true)
  115. : mutations
  116. }
  117. _setupMiddlewares (middlewares, state) {
  118. this._middlewares = [devtoolMiddleware].concat(middlewares)
  119. this._needSnapshots = middlewares.some(m => m.snapshot)
  120. const initialSnapshot = this._prevSnapshot = this._needSnapshots
  121. ? deepClone(state)
  122. : null
  123. // call init hooks
  124. this._middlewares.forEach(m => {
  125. if (m.onInit) {
  126. m.onInit(m.snapshot ? initialSnapshot : state)
  127. }
  128. })
  129. }
  130. }
  131. /**
  132. * Exposed install method
  133. */
  134. Vuex.install = function (_Vue) {
  135. Vue = _Vue
  136. }