入门Vuex,手把手教你写实用案例

145 阅读3分钟

简介

Vuex 是 Vue 的状态管理模式+库。使用 Vuex,你可以确保状态变更的明确性和可追踪性,使多人协作开发的大型应用变得更加容易维护和理解。同时,它也能帮助你更好地组织和管理你的应用状态。

Vuex官网:Vuex image.png

Vuex 的核心概念

  • state 数据状态
  • getters 类似于计算属性,在此对状态进行包装
  • mutation 同步更改数据状态,接收一个必传参数state
  • action 异步更改状态,通过调用mutation方法来间接更改state的状态,接收一个默认参数context (context.ommit('方法名','参数'))
  • modules 挂载别的模块。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter。

在vue中如何使用vuex

安装vuex

yarn add vuex

在Vue实例中挂载Vuex Store

// main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

Vue.config.productionTip = false

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

创建Vuex Store

在你的项目结构中,创建一个新的文件夹(例如store),并在其中创建一个名为index.js的文件。在这个文件中,你将定义你的Vuex store。

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    count: 0,
    name: '岚'
  },
  getters: {
  },
  mutations: {
    changeCount(state) {
      state.count++
    },
    changeName(state, newName) {
      state.name = newName
    }
  },
  actions: {
    changeNameAction(context, newName) {
      setTimeout(() => {
        context.commit('changeName', newName)
      }, 500)
    }
  },
  modules: {
  }
})

在组件中使用

可以在Vue组件中通过this.$store来访问Vuex store了。但更常见的做法是使用mapStatemapGettersmapMutationsmapActions辅助函数来帮助你更简洁地管理状态。

  • 组件中获取state中数据的方法
  1. 直接使用$store.state.状态名
  2. 使用mapState,用mapState将store中的state映射到组件中...mapState(['状态名'])如果在组件中命名有冲突时可以使用别名...mapState({'组件中使用的别名':'store中的组件名'})
  • 在组件中调用getter的方法
  1. $store.getters.状态名
  2. 使用mapGetter
  • 在组件中调用mutation的方法
  1. $store.commit('store中的方法名','参数')触发
  2. 使用mapMutations()
  • 在组件中调用action的方法
  1. $store.dispatch('方法名','参数')触发
  2. 使用mapActions()
<template>
  <div class="about">
    <h1>This is an about page</h1>
    <p>{{ $store.state.name }} <button @click="changeName('山风')">点我改变name</button> </p>
    <button @click="changeC">点我++{{ $store.state.count }} = {{num}}</button>
  </div>
</template>
<script>
import { mapState, mapMutations, mapActions } from 'vuex'
export default {
  computed: {
    ...mapState(['name']),
    ...mapState({num:'count'}),//在组件中使用num就可以访问到store中的count
  },
  methods: {
    ...mapMutations(['changeCount']),
    ...mapActions(['changeNameAction']),
    changeName(newName) {
      this.changeNameAction(newName)
    },
    changeC() {
      this.changeCount()
    }
  }
}
</script>

分模块

在store文件夹下,创建一个新的文件夹(例如modules),并在其中创建一个名为name.js的文件。在这个文件中,你将定义你的Module Vuex store。

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const nameModule = {
    namespaced: true,
    state: {
        name: '岚'
    },
    getters: {
    },
    mutations: {
        changeName(state, newName) {
            state.name = newName
        }
    },
    actions: {
        changeNameAction(context, newName) {
            setTimeout(() => {
                context.commit('changeName', newName)
            }, 500)
        }
    },
}
export default nameModule

将这个nameModule引入到我们的index中

import Vue from 'vue'
import Vuex from 'vuex'
import nameModule from './modules/name'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    count:0,
  },
  getters: {
  },
  mutations: {
    changeCount(state){
      state.count++
    },
  },
  actions: {
  },
  modules: {
    nameModule
  }
})

这时我们在组件中该如何使用呢?

  1. 对于action,mutation,getters,是在模块中还是在全局里使用方式都相同,但对于state中的状态,模块中的state多一层模块名 $state.state.模块名.状态名 (根state中的格式为:$state.state.状态名
  2. 可以通过开启命名空间(namespaced:true)来隔离各个模块。开启命名空间后的模块中的getters,mutations,actions的使用方法会发生改变,但不开启命名空间的state的使用方法与开启命名空间的state的使用方法一致。
  3. 以下是在组件中使用已开启命名空间后的module中的方法以及获取状态的方法:
  • ...mapState({状态名: state => state.模块名.状态名})
  • ...mapState('模块名',{状态名: state => state.状态名})
  • ...mapGetters(['模块名/状态名'])
  • ...mapGetters('模块名',['状态名'])
  • this.$store.dispatch('模块名/方法名')
<template>
  <div class="about">
    <h1>This is an about page</h1>
    <p>{{ $store.state.nameModule.name }} <button @click="changeName('山风')">点我改变name</button> </p>
    <button @click="changeC">点我++{{ $store.state.count }}</button>
  </div>
</template>
<script>
import { mapState, mapMutations, mapActions } from 'vuex'
export default {
  computed: {
    ...mapState('nameModule', ['name'])
  },
  methods: {
    ...mapMutations(['changeCount']),
    ...mapActions('nameModule', ['changeNameAction']),
    changeName(newName) {
      console.log(newName);
      this.changeNameAction(newName)
    },
    changeC() {
      this.changeCount()
    }
  }
}
</script>