日志总结 - 2018-06-06

Vuex学习笔记

初始化

  1. html引入

        <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
        <script src="https://unpkg.com/vuex@3.0.1/dist/vuex.js"></script>
        <!-- 或者下载下来文件夹引入 -->
    
  2. NPM

      npm install vuex --save
    
      import Vue from 'vue'
      import Vuex from 'vuex'
    
      Vue.use(Vuex)
    

what?

  1. Vuex是一个专为Vue.js应用程序开发的状态管理模式, 采用集中式存储管理应用的所有组件的状态, 并以相应的规则保证状态以一种可预测的方式发生变化
  2. 我的理解: Vuex就是提取各个组件共同需要用的数据和函数, 类似共享属性和方法, 方便在各个组件间的数据通信
  3. 状态自管理应用包含三个部分:
    3.1 state: 驱动应用的数据源;(data)
    3.2 view: 以声明方式将state映射到视图;(template)
    3.3 actions: 响应在view上的用户输入导致的状态变化;(methods)
    3.4 单向数据流: View --> Actions --> State --> View;(多组件共享状态会破坏单向数据流的简洁性)
  4. Vuex基本思想: 把组件的共享状态抽取出来, 以一个全局单例模式管理, 组件树构成一个巨大的"视图"


    Vuex基本思想

核心

  1. Store
    1. 每一个Vuex应用的核心就是store(仓库), 基本上就是一个容器, 包含应用的大部分状态(state)
      1.1.1 Vuex的状态存储是响应式的
      1.1.2 改变store中的状态的唯一途径就是显式提交(commit) mutation
        var store = new Vuex.Store({
          state: {
            count: 0
          },
          mutations: {
            increment: function(state){
              state.count++
            }
          }
        })
    
        // store.commit('increment')
        // console.log(store.state.count) // -> 1
        // 最基本的Vuex计数应用Demo
        // https://jsfiddle.net/n9jmu5v7/1269/
    
  2. State
    1. 单一状态树: 用一个对象包含全部的应用层级状态, 唯一数据源(每一个应用仅仅包含一个store实例)
    2. 在Vue组件中获取Vuex状态(获取state里面的数据)的方法:
      1. 计算属性: computed
            组件中
            computed: {
              count: function(){
                  return this.$store.state.count
              }
            }
        
      2. 辅助函数: mapState(一个组件获取多个状态时候)
            在组件中
            computed: Vuex.mapState({
              count: function(state){
                return state.count
              },
              countAlias: 'count',
              countPlusLocalState: function(state){
                return state.count+this.localCount
              }
            })
            对象展开运算符
            computed: {
              ...mapState(['state里面的参数','state里面的参数'])
            },
            mounted: function(){
                console.log(this.上面...mapState里面的参数就可以获取到)
            }
        
      3. 注意: 封装成组件的局部状态
  3. Getter
    1. 需要从store中的state中派生出一些状态, 例如对列表进行过滤并计数;
    2. 相当于store的计算属性, 接受state作为第一个参数, 通过store.getters访问;
    3. getters做为第二个参数,调用getters;
    4. 组件中使用: this.$store.getters.参数名
    5. 通过方法访问, 让getter返回一个函数, 实现给getter传参 (在对store里面的数组进行查询时非常有用)
    6. 注意, getter通过方法访问, 每次都会去进行调用, 而不会缓存结果
    7. mapGetters辅助函数: 映射局部计算属性
  4. Mutation
    1. 更改Vuex的store的状态唯一方法是提交mutation, 每一个mutation都有一个字符串的事件类型和一个回调函数, 接受state第一个参数;
    2. 提交载荷: 第二个参数以后为载荷参数或者载荷对象
    3. 遵守响应规则:
      1. 最好提前在store中初始化所需属性;
      2. 添加新属性时, 用Vue.set(obj, 'newProp', 123) 或者以新对象替换老的 state.obj = {...state.obj, newProp:123}
    4. Mutation 必须是同步函数
    5. 组件提交mutation this$store.commit('xxx'), 或者使用mapMutations辅助函数
  5. Action
    1. Action类似于mutation, 不同在于Action提交的是mutation, 而不是直接修改状态, 可以异步操作;
    2. context对象, context.commit , context.state, context.getters
    3. 分发Action: store.dispatch('increament')
    4. 组件分发: this.$store.dispatch('...')
  6. Module
    1. 将store分割成模块, 每个模块拥有自己的state, mutation, action, getter
          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 的状态 */
          store.state.b /* -> moduleB 的状态 */
      
    2. 模块的局部状态:对于模块内部的mutation和getter, 接收的都是模块的局部状态对象;而action通过context.state & context.rootState; getter的根节点状态作为第三个参数暴露
          const moduleA = {
              state: {
                  count: 0
              },
              mutations: {
                  increment(state){
                      /* state 对象是模块的局部状态 */
                      state.count++
                  }
              },
              getters: {
                  doubleCount(state){
                      return state.count*2
                  },
                  sumWithRootCount(state, getters, rootState){
                      return state.count+rootState.count
                  }
              },
              actions: {
                  incrementIfOddOnRootSum({state, commit, rootState}){
                      if((state.count + rootState.count) %2===1){
                          commit('increment')
                      }
                  }
              }
          }
      
    3. 命名空间:默认情况下,模块内部的action、mutation和getter是注册在全局命名空间的——多模块对同一mutation或action做出响应;如果需要封装和复用,添加 namespaced: true, 对getters、actions、mutations有影响
          const store = new Vuex.Store({
              modules: {
                  account: {
                      namespaced: true,
      
                      state: {...}, /* 模块内的状态已经是嵌套的了,使用 namespaced 属性不会对其产生影响 */
                      getters: {
                          isAdmin(){...0}  /* -> getters['account/isAdmin'] */
                      },
                      actions: {
                          login () { ... } /* -> dispatch('account/login') */
                      },
                      mutations: {
                          login () { ... } /* -> commit('account/login') */
                      },
      
                      /* 嵌套模块 */
                      modules: {
                          /* 继承父模块的命名空间 */
                          myPage: {
                              state: { ... },
                              getters: {
                                  profile () { ... } /* -> getters['account/profile'] */
                              }
                          },
      
                          /* 进一步嵌套命名空间 */
                          posts: {
                              namespaced: true,
      
                              state: { ... },
                              getters: {
                                  popular () { ... } /* -> getters['account/posts/popular'] */
                              }
                          }
                      }
                  }
              }
          })
      
    4. 带命名空间的模块内访问全局内容:
      1. 全局state和getter, rootState和rootGetter传入getter, 通过context对象属性传入action
      2. 全局命名空间内分发action或者提交mutation,将{root: true} 作为三参传给dispatch或commit
            commit('somMutation', null, {root: true})
        
    5. 带命名空间模块注册全局action: 添加root:true, 放在函数handler中
          {
              actions: {
                  someOhterAction({dispatch}){
                      dispatch('someAction')
                  }
              },
              modules: {
                  foo: {
                      namespaced: true,
                      actions: {
                          someAction: {
                              root: true,
                              handler(namespacedContext, payload){
                                  ...
                              }
                          }
                      }
                  }
              }
          }
      
    6. 带命名空间的绑定函数
          computed: {
              ...mapState({
                  a: state => state.some.nested.module.a,
                  b: state => state.some.nested.module.b,
              })
          },
          methods: {
              ...mapActions([
                  'some/nested/module/foo',
                  'some/nested/module/bar',
              ])
          }
      
          /* 简化 */
          computed: {
              ...mapState('some/nested/module', {
                  a: state => state.a,
                  b: state => state.b
              })
          },
          methods: {
              ...mapActions('some/nested/module', [
                  'foo',
                  'bar'
              ])
          }
      
          createNamespacedHelpers('some/nested/module')
      
    7. 模块重用: 把state写成函数形式, 避免状态对象模块间数据互相污染
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 安装 npm npm install vuex --save 在一个模块化的打包系统中,您必须显式地通过Vue.u...
    萧玄辞阅读 2,964评论 0 7
  • State 单一状态树 Vuex 使用单一状态树——是的,用一个对象就包含了全部的应用层级状态。至此它便作为一个“...
    peng凯阅读 710评论 2 0
  • Vuex是什么? Vuex 是一个专为 Vue.js应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件...
    萧玄辞阅读 3,148评论 0 6
  • Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应...
    白水螺丝阅读 4,684评论 7 61
  • Vuex 是什么? Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有...
    skycolor阅读 873评论 0 1