zoukankan      html  css  js  c++  java
  • Vuex学习心得

    最近公司项目中使用Vuex做状态管理,就全面温习了一遍文档,然后在项目使用中遇到一些常见问题就一一总结下。

    一、由来

    我们知道Vue中数据是自顶向下单向流动的,但是以下两种情况单向数据流实现起来十分繁琐且不易维护:

    1. 多个视图依赖同一状态;
    2. 来自不同视图需要变更统一状态。

    因此,Vuex诞生了。我们需要把不同组件的共享状态抽离出来,放在全局单例中管理,这样我们的组件树构成一个巨大的“视图网”,任何组件都可以获取共享状态并且以相同的规则变更状态。

    Vuex都有一个“store”,包含应用中大部分状态。Vuex和全局对象有以下两点不同

    1. Vuex中的状态是响应式的,只要store中的状态发生改变,其他组件也会得到高效更新;
    2. store中的状态不能直接改变,只能显式的提交mutation来更新。

    二、概念

    State

    Vuex使用单一状态树,state作为应用的唯一数据源而存在。当我们需要从store获取状态时,只需在组件计算属性中直接返回即可。使用mapState辅助函数可以更方便我们生成计算属性。

    state.js

    const state = {
      count: 0
    }
    
    export default state

    component.js

    import { mapState } from 'vuex'
    export default {
      name: 'Vuex',
      data() {
        return {
        }
      },
      computed: {
        localComputed: () => {},
        ...mapState({
          count: state => state.count
        })
      },
      methods: {
      }
    }

    Vuex并不意味着所有状态都必须放在store中,若有些状态属于单个组件,最好作为组件的局部状态存在为好。

    Getters

    getter通俗来讲就是state的计算属性,方便我们从state中派生出一些状态出来。getter接受state、getter作为其第一个、第二个参数。

    const getters = {
      derCount: state => {
          return state.count+1
      },
      doneLists: (state, getters) => {
          return state.todoLists.filter(list => list.status)
      },
      todoCount: (state, getters) => {
          return state.todoLists.length - getters.doneLists.length
      },
    }
    
    export default getters

    获取getter对象可通过属性访问this.$store.getters.doneLists,同样我们可以通过mapGetters辅助函数获取:

    ...mapGetters([
      'doneLists',
      'todoCount'
    ])

     Mutation

    更改 Vuex 的 store 中的状态的唯一方法是提交 mutation,只有mutation中才能直接操作state。Vuex 中的 mutation 非常类似于事件,不能直接调用mutation handler。你需要先在mutattion中注册handler,然后在action或组件中调用此函数。每个mutation接受state,payload作为其第一个、第二个参数。

    const mutations = {
      addCount: (state) => {
          state++
      },
      updateList: (state, index) => {
          let updateList = state.todoLists[index]
          let status = updateList.status
          status = status?0:1
          state.todoLists[index].status = status
      }
    }
    
    export default mutations

    Vuex的store是响应式的,因此使用mutation时注意以下事项:

    1. 最好提前在你的 store 中初始化好所有所需属性;
    2. mutation必须是同步函数;
    3. 当需要在对象上添加新属性时,你应该:
    • 使用 Vue.set(obj, 'newProp', 123), 或者
    • 以新对象替换老对象。例如,利用 stage-3 的对象展开运算符我们可以这样写:
    state.obj = { ...state.obj, newProp: 123 }

    你可以在组件中使用 this.$store.commit('xxx') 提交 mutation,或者使用 mapMutations 辅助函数将组件中的 methods 映射为 store.commit

      methods: {
        localMethods() {
    
        },
        ...mapMutations([
          'updateList',
          'addCount'
        ])
      }

    Action

    action类似于mutation,不同之处在于:

    1. action提交的是mutation,而不是直接变更状态,无法直接操作state;
    2. action支持异步操作。

    action函数接受和store相同属性、方法的context对象,同样支持提交载荷方式。action通过store.dispatch的方式来分发。

    const actions = {
      addCountAsync: ({commit}) => {
          commit('addCount')
      },
      deleteListAsync: ({commit}, index) => {
          setTimeout(() => {
            commit('deleteList',index)
          },1000)
      }
    }
    
    export default actions

    你在组件中使用 this.$store.dispatch('xxx') 分发 action,或者使用 mapActions 辅助函数将组件的 methods 映射为 store.dispatch 调用(需要先在根节点注入 store

    ...mapActions([
      'addCountAsync',
      'deleteListAsync'  //将this.deleteListAsync()映射为this.$store.dispatch('deleteListAsync')
    ]),

    Module

    Vuex是单一状态树,应用所有状态都集中在一个比较大的对象中。当项目足够大时,store对象会变得很臃肿。Vuex允许我们分割store为子模块,每个modules都拥有自己的state、getters、mutations、actions、mudules。

    如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。

    • getter接受参数依次为局部state、getters、根节点状态rootState、根节点rootGetter;
    • mutation局部状态state、payload作为第一、第二个参数;
    • action局部状态为context.state,根节点状态为context.rootState。{state,commit,rootState,rootGetters};
    const state = {
      bookLists: [
        {name: '三国演义', status: 1},
        {name: '西游记', status: 1},
        {name: '红楼梦', status: 0},
        {name: '水浒传', status: 0}
      ]
    }
    
    // getters
    const getters = {
      /**
       * @param  {[type]} state、getters       [局部状态]
       * @param  {[type]} rootState、rootGetters   [根节点状态]
       */
      readBook: (state, getters, rootState, rootGetters) => {
        return state.bookLists.filter(list => list.status)
      }
    }
    
    // mutations
    const mutations = {
      // state 局部状态
      readOver (state, { index }) {
        state.bookLists[index].status = 1
      },
      reRead (state, { index }) {
        state.bookLists[index].status = 0
      },
      delete (state, { index }) {
        state.bookLists.splice(index, 1)
      }
    }
    
    // actions
    const actions = {
      /**
       * dispatch、commit局部化
       * 提交是接受root访问根dispatch、commit
       */
      deleteAsync ({ dispatch, commit, state, getters, rootState, rootGetters }, index) {
        commit('delete',{index:index})
        commit('reduceLast',null,{root:true})
      }
    }
    
    export default {
      namespaced: true,
      state,
      getters,
      mutations,
      actions
    }

    若在子模块内部想在全局命名空间提交commit、分发action,将{root:true}作为第三参数传给commit、dispatch即可。 

    当在组件中使用带命名空间的子模块时,可以将空间名称作为第一参数传给相应map函数:

    computed:

    ...mapState('book', {
      bookLists: state => state.bookLists,
    }),

    methods:

    ...mapMutations('book', [
      'readOver',变更状态
      'reRead'
    ]),
    ...mapActions('book', [
      'deleteAsync',
    ]),

    三、使用技巧

    在严格模式下使用Vuex时,使用v-model将state与表单绑定,修改表单值会出现报错。严格模式规定无论何时修改state状态且不是由于mutation引起就会抛出错误。这时我们可以在组件中将所需状态深拷贝一份,进行模板渲染或操作变更,最后再深拷贝一份提交mutation变更状态。这样组件内的操作就不受state影响。

    获取深拷贝状态:

    stateData() {
      let _stateData = JSON.parse(JSON.stringify(this.$store.state.stateData))
      this.data = _stateData
      return this.$store.state.stateData
    }

    提交mutation:

    setData(data) {
      let setData = JSON.parse(JSON.stringify(data))
      this.$store.commit('setStateData',setData)
    }
  • 相关阅读:
    jquery对象中 “冒号” 详解
    vscode自定以vue代码模板
    Vue项目开发环境proxyTable反向代理,生产环境下服务接口地址找不到的解决
    JS函数的节流和防抖
    BFC-块状格式化上下文
    c# 鼠标钩子
    C# 以管理员身份运行WinForm程序
    样式更换
    Revert to this revision 和 Revert changes from this revision 区别
    人工智能几行代码实现换脸
  • 原文地址:https://www.cnblogs.com/lodadssd/p/10663249.html
Copyright © 2011-2022 走看看