vuex基础知识总结

132 阅读2分钟

vuex

核心概念

State

单一状态树

单状态树和模块化并不冲突

   // 1.从 store 实例中读取状态最简单的方法就是在计算属性 (opens new window)中返回某个状态:
    computed: {
        count(){
            return this.$store.state.count
        }
    },
    // 2.当一个组件需要获取多个状态的时候,我们可以使用 mapState 辅助函数帮助我们生成计算属性
    computed: mapState({
        // 箭头函数可使代码更简练
         count: state => state.count,
    }),
    // 3.当映射的计算属性的名称与 state 的子节点名称相同时,我们也可以给 mapState 传一个字符串数组。
    computed: mapState(
          // 映射 this.count 为 store.state.count
        ['count']
        
    ),
    // 4.对象展开运算符
   // mapState 函数返回的是一个对象。我们如何将它与局部计算属性混合使用呢?
   computed: {
        localComputed () { /* ... */ },
        ...mapState(['count'])
       
   },

Getter

有时候我们需要从 store 中的 state 中派生出一些状态,例如对列表进行过滤并计数:

computed: {
  doneTodosCount () {
    return this.$store.state.todos.filter(todo => todo.done).length
  }
}

Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。

Getter 接受 state 作为其第一个参数:

const store = new Vuex.Store({
  state: {
    todos: [
      { id: 1, text: '...', done: true },
      { id: 2, text: '...', done: false }
    ]
  },
  getters: {
    doneTodos: state => {
      return state.todos.filter(todo => todo.done)
    }
  }
})

Getter 也可以接受其他 getter 作为第二个参数:

getters: {
  // ...
  doneTodosCount: (state, getters) => {
    return getters.doneTodos.length
  }
}

组件中使用

计算属性
computed: {
  doneTodosCount () {
    return this.$store.getters.doneTodosCount
  }
}


mapGetters 辅助函数
import { mapGetters } from 'vuex'

export default {
  computed: {
  // 使用对象展开运算符将 getter 混入 computed 对象中
    ...mapGetters([
      'doneTodosCount',
      'anotherGetter',
    ])
  }
}

Mutation

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Mutation 必须是同步函数。

提交载荷(Payload)

你可以向 store.commit 传入额外的参数,即 mutation 的 载荷(payload).在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读:

// mutations
mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}

//组件中使用
store.commit('increment', {
  amount: 10
})


//对象风格的提交方式
store.commit({
  type: 'increment',
  amount: 10
})
Mutation 需遵守 Vue 的响应规则
  1. 最好提前在你的 store 中初始化好所有所需属性。
  2. 当需要在对象上添加新属性时,你应该使用 Vue.set(obj, 'newProp', 123), 或者以新对象替换老对象。例如,利用对象展开运算符 (opens new window)我们可以这样写:(redux中也是这样的)
state.obj = { ...state.obj, newProp: 123 }
使用常量替代 Mutation 事件类型
// mutation-types.js
export const SOME_MUTATION = 'SOME_MUTATION'
// store.js
import Vuex from 'vuex'
import { SOME_MUTATION } from './mutation-types'

const store = new Vuex.Store({
  state: { ... },
  mutations: {
    // 我们可以使用 ES2015 风格的计算属性命名功能来使用一个常量作为函数名
    [SOME_MUTATION] (state) {
      // mutate state
    }
  }
})

Action

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。

Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。但是context 对象不是 store 实例本身了。

分发 Action

  //以载荷形式分发  
  incrementAsync(){
        this.$store.dispatch('incrementAsync',{count:10})
    }
  //以对象形式分发
  incrementAsync(){
        this.$store.dispatch({
                type:'incrementAsync',
                count:10
            })
    }

 //借助辅助函数mapActions

 // 传参,这个只是映射,在函数调用的时候传参
   ...mapActions(['incrementAsync'])

组合 Action

Module

将每个功能单独放在一个module中

定义
const moduleA = {
  //命名空间
  namespaced: true,
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
   namespaced: true,
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
模块化带命名空间组件中的取值(参照官网中 带命名空间的绑定函数 的介绍)
//state

 computed: {
      // count(){
      //     return this.$store.state.count.count
      // },
      ...mapState('count',['count']),     
  },

//getters

      // expandNum(){
      //     return this.$store.getters['count/expandNum']
      // }
      
      ...mapGetters('count',['expandNum'])

//mutations

       increment() {
          this.$store.commit('count/increment',{count:10})
      },



      //传参一:调用时传参
       <button @click="increment({count:10})">点我加10</button>
      ...mapMutations('count',['increment']), //注意:这里只是映射了方法

      //传参二:方法中传参
       <button @click="handleIncrement">点我加10</button>
       ...mapMutations('count',['increment']),
       //注意,下面这个方法名不要与commit中的方法同名
       handleIncrement(){
            this.increment({
                count:10
            })
        },

//Action
      incrementAsync(){
            this.$store.dispatch('count/incrementAsync',{count:10})        
      },

      //传参一:调用时传参
        <button @click="incrementAsync({count:10})">点我过1s后再加</button>
      ....mapActions('count',['incrementAsync']), //注意:这里只是映射了方法

      //传参二:方法中传参
       <button @click="handleIncrement">点我加10</button>
       ...mapActions('count',['incrementAsync']),

        //注意,下面这个方法名不要与dispatch中的方法同名
        handleIncrementAsync(){
               this.incrementAsync({
                   count:10
               })
          }

      //传参二也可以这样写
      ...mapActions(['count/incrementAsync']),
       handleIncrementAsync(){
              this['count/incrementAsync']({
                   count:10
              })
          

模块的局部状态
  • 对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态对象。
  • 对于模块内部的 getter,根节点状态会作为第三个参数暴露出来。
  • 同样,对于模块内部的 action,局部状态通过 context.state 暴露出来,根节点状态则为 context.rootState
在带命名空间的模块内访问全局内容
  • 如果你希望使用全局 state 和 getter,rootState 和 rootGetters 会作为第三和第四参数传入 getter,也会通过 context 对象的属性传入 action。

  • 若需要在全局命名空间内分发 action 或提交 mutation,将 { root: true } 作为第三参数传给 dispatch 或 commit 即可。

modules: {
  foo: {
    namespaced: true,

    getters: {
      // 在这个模块的 getter 中,`getters` 被局部化了
      // 你可以使用 getter 的第四个参数来调用 `rootGetters`
      someGetter (state, getters, rootState, rootGetters) {
        getters.someOtherGetter // -> 'foo/someOtherGetter'
        rootGetters.someOtherGetter // -> 'someOtherGetter'
      },
      someOtherGetter: state => { ... }
    },

    actions: {
      // 在这个模块中, dispatch 和 commit 也被局部化了
      // 他们可以接受 `root` 属性以访问根 dispatch 或 commit
      someAction ({ dispatch, commit, getters, rootGetters }) {
        getters.someGetter // -> 'foo/someGetter'
        rootGetters.someGetter // -> 'someGetter'

        dispatch('someOtherAction') // -> 'foo/someOtherAction'
        dispatch('someOtherAction', null, { root: true }) // -> 'someOtherAction'

        commit('someMutation') // -> 'foo/someMutation'
        commit('someMutation', null, { root: true }) // -> 'someMutation'
      },
      someOtherAction (ctx, payload) { ... }
    }
  }
}

在带命名空间的模块注册全局 action

若需要在带命名空间的模块注册全局 action,你可添加 root: true,并将这个 action 的定义放在函数 handler 中。例如:

{
  actions: {
    someOtherAction ({dispatch}) {
      dispatch('someAction')
    }
  },
  modules: {
    foo: {
      namespaced: true,

      actions: {
        someAction: {
          root: true,
          handler (namespacedContext, payload) { ... } // -> 'someAction'
        }
      }
    }
  }
}