Skip to content

安装

  1. yarn add vuex

  2. 集成

    js
    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex)
    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex)

简单使用

文件配置

main.js

js
import Vue from 'vue'
import App from './App.vue'
import Vuex from 'vuex'
import store from './store'

Vue.use(Vuex)

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
  // 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件
  store: store
}).$mount('#app')
import Vue from 'vue'
import App from './App.vue'
import Vuex from 'vuex'
import store from './store'

Vue.use(Vuex)

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
  // 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件
  store: store
}).$mount('#app')

store/index.js

js
import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export default new Vuex.Store({
  //类似data,存储共享数据  
  state: {
    count: 100
  },
  //类似于计算属性computed,可以对数据进行进一步加工
  getters: {
    tripleCount (state) {
      return state.count * 3
    }
  },
  //方法methods,用来注册改变数据状态
  mutations: {},
  //异步操作,解决异步改变共享数据
  actions: {},
  //模块,用来注册改变数据状态
  modules: {}
});
import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export default new Vuex.Store({
  //类似data,存储共享数据  
  state: {
    count: 100
  },
  //类似于计算属性computed,可以对数据进行进一步加工
  getters: {
    tripleCount (state) {
      return state.count * 3
    }
  },
  //方法methods,用来注册改变数据状态
  mutations: {},
  //异步操作,解决异步改变共享数据
  actions: {},
  //模块,用来注册改变数据状态
  modules: {}
});

staus

status用于状态的存储。

直接访问:

html
{{ $store.state.count }}
{{ $store.state.count }}

在computed中使用:

js
...
computed: {
    doubleCount () {
      return this.$store.state.count * 2
    }
  }
...
...
computed: {
    doubleCount () {
      return this.$store.state.count * 2
    }
  }
...

vuex提供了mapState 方法,用于简化冗余代码

js
// 使用mapState
computed: mapState({
    doubleCount: state => state.count * 2,
    quadraCount: state => state.count * 4,
  })
... 

 //使用对象展开运算符,不耽误其他变量
computed: {
  ...mapState({
  doubleCount: state => state.count * 2,
  addLocalNum (state) {
    return state.count + this.localNum
  }
})
// 使用mapState
computed: mapState({
    doubleCount: state => state.count * 2,
    quadraCount: state => state.count * 4,
  })
... 

 //使用对象展开运算符,不耽误其他变量
computed: {
  ...mapState({
  doubleCount: state => state.count * 2,
  addLocalNum (state) {
    return state.count + this.localNum
  }
})

getter

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

直接访问

html
tripleCount:{{ $store.getters.tripleCount }} <br>
tripleCount:{{ $store.getters.tripleCount }} <br>

或者

computed: {  
    calcCountExt() {
      return this.$store.getters.calcCountExt
    },
    getCountAddValue() {
      return this.$store.getters.getCountAddValue(10)
    },
    ...mapGetters({
      // calcCountExt 相当于  this.$store.getters.calcCountExt
      countAddValue: 'calcCountExt'
    }),
    ...mapGetters([
      'doneTodosCount',
      'anotherGetter',
      // ...
    ])
  },
computed: {  
    calcCountExt() {
      return this.$store.getters.calcCountExt
    },
    getCountAddValue() {
      return this.$store.getters.getCountAddValue(10)
    },
    ...mapGetters({
      // calcCountExt 相当于  this.$store.getters.calcCountExt
      countAddValue: 'calcCountExt'
    }),
    ...mapGetters([
      'doneTodosCount',
      'anotherGetter',
      // ...
    ])
  },

同样提供了mapGetters方法用来简化代码。

Mutation

用于修改状态。

Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:

使用举例:

javascript
  mutations: {
    incrementCount (state) {
      // 变更状态
      state.count++
    },
    // 支持添加额外参数
    countMultiply (state, n) {
      state.count = state.count * n
    }
  },
    
// 调用
this.$store.commit('countMultiply',2);
  mutations: {
    incrementCount (state) {
      // 变更状态
      state.count++
    },
    // 支持添加额外参数
    countMultiply (state, n) {
      state.count = state.count * n
    }
  },
    
// 调用
this.$store.commit('countMultiply',2);

一条重要的原则就是要记住 mutation 必须是同步函数

提供了函数mapMutations 方便用户操作:

js
import { mapMutations } from 'vuex'

export default {
  // ...
  methods: {
    ...mapMutations([
      'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`

      // `mapMutations` 也支持载荷:
      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
    ]),
    ...mapMutations({
      add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
    })
  }
}
import { mapMutations } from 'vuex'

export default {
  // ...
  methods: {
    ...mapMutations([
      'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`

      // `mapMutations` 也支持载荷:
      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
    ]),
    ...mapMutations({
      add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
    })
  }
}

action

Action 类似于 mutation,不同在于:

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

mutation中定义的方法必须同步执行,action没有这个限制。

js
actions: {
  increment ({ commit }) {
    commit('increment')
  }
}
// 调用
// store.dispatch('increment')
actions: {
  increment ({ commit }) {
    commit('increment')
  }
}
// 调用
// store.dispatch('increment')

Actions 支持同样的载荷方式和对象方式进行分发:

js
// 以载荷形式分发
store.dispatch('incrementAsync', {
  amount: 10
})

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

// 以对象形式分发
store.dispatch({
  type: 'incrementAsync',
  amount: 10
})

来看一个更加实际的购物车示例,涉及到调用异步 API分发多重 mutation

javascript
actions: {
  checkout ({ commit, state }, products) {
    // 把当前购物车的物品备份起来
    const savedCartItems = [...state.cart.added]
    // 发出结账请求,然后乐观地清空购物车
    commit(types.CHECKOUT_REQUEST)
    // 购物 API 接受一个成功回调和一个失败回调
    shop.buyProducts(
      products,
      // 成功操作
      () => commit(types.CHECKOUT_SUCCESS),
      // 失败操作
      () => commit(types.CHECKOUT_FAILURE, savedCartItems)
    )
  }
}
actions: {
  checkout ({ commit, state }, products) {
    // 把当前购物车的物品备份起来
    const savedCartItems = [...state.cart.added]
    // 发出结账请求,然后乐观地清空购物车
    commit(types.CHECKOUT_REQUEST)
    // 购物 API 接受一个成功回调和一个失败回调
    shop.buyProducts(
      products,
      // 成功操作
      () => commit(types.CHECKOUT_SUCCESS),
      // 失败操作
      () => commit(types.CHECKOUT_FAILURE, savedCartItems)
    )
  }
}

使用mapActions简化代码

javascript
import { mapActions } from 'vuex'

export default {
  // ...
  methods: {
    ...mapActions([
      'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`

      // `mapActions` 也支持载荷:
      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
    ]),
    ...mapActions({
      add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
    })
  }
}
import { mapActions } from 'vuex'

export default {
  // ...
  methods: {
    ...mapActions([
      'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`

      // `mapActions` 也支持载荷:
      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
    ]),
    ...mapActions({
      add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
    })
  }
}

store.dispatch 可以处理被触发的 action 的处理函数返回的 Promise

据此,可以方便进行组合:

js
actions: {
  // ...假设someOtherMutation返回的是promise
  actionB ({ dispatch, commit }) {
    return dispatch('actionA').then(() => {
      commit('someOtherMutation')
    })
  }
}

// or 
// 假设 getData() 和 getOtherData() 返回的是 Promise
actions: {
  async actionA ({ commit }) {
    commit('gotData', await getData())
  },
  async actionB ({ dispatch, commit }) {
    await dispatch('actionA') // 等待 actionA 完成
    commit('gotOtherData', await getOtherData())
  }
}
actions: {
  // ...假设someOtherMutation返回的是promise
  actionB ({ dispatch, commit }) {
    return dispatch('actionA').then(() => {
      commit('someOtherMutation')
    })
  }
}

// or 
// 假设 getData() 和 getOtherData() 返回的是 Promise
actions: {
  async actionA ({ commit }) {
    commit('gotData', await getData())
  },
  async actionB ({ dispatch, commit }) {
    await dispatch('actionA') // 等待 actionA 完成
    commit('gotOtherData', await getOtherData())
  }
}

Module

module允许将一个vuex对象拆分成n个对象。每个对象有各自的mutation、action、getter、module。

示例代码:

js
const state = {
  userId:'',
  userName:''
}

// getters
const  getters = {
  // 获取用户信息
  getUserInfo(){
    return state;
  }
}

// actions
const actions = {}

// mutations
const mutations = {
  setUserInfo(state,payload) {
    state.userId = payload.userId;
    state.userName = payload.userName;
  }
}

export default {
  namespaced: true,
  state,
  getters,
  actions,
  mutations
}

// --- module引入
 modules: {
    user1: user
 }
const state = {
  userId:'',
  userName:''
}

// getters
const  getters = {
  // 获取用户信息
  getUserInfo(){
    return state;
  }
}

// actions
const actions = {}

// mutations
const mutations = {
  setUserInfo(state,payload) {
    state.userId = payload.userId;
    state.userName = payload.userName;
  }
}

export default {
  namespaced: true,
  state,
  getters,
  actions,
  mutations
}

// --- module引入
 modules: {
    user1: user
 }

直接访问访问state:

js
computed: {
    //使用对象展开运算符,不耽误其他变量
    userInfo () {
      return this.$store.state.user1
    }
}
computed: {
    //使用对象展开运算符,不耽误其他变量
    userInfo () {
      return this.$store.state.user1
    }
}

这里的namespaced的含义是添加一个命名空间。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。例如:

js
this.$store.commit('user1/setUserInfo', {
  userId:'1'
  userName:'2'
})
this.$store.commit('user1/setUserInfo', {
  userId:'1'
  userName:'2'
})

参考

文档地址 https://vuex.vuejs.org/

vuex-demo 入门解析 https://juejin.cn/post/6844904146038947854