10 分钟学会 Vuex
Vuex 全局的状态统一管理,解决组件之间状态共享和数据通信的问题。
第一步
store.js
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) // 使用插件 // 导出 store 实例 export default new Vuex.Store({ state: { }, mutations: { }, actions: { } })
第二步
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, // 增加 store 属性,值是导出 store 的实例 render: h => h(App) }).$mount('#app')
通过上面两个步骤,每个组件中都有了 $store
属性,就是我们创建的容器。里面有 commit
, dispatch
, state
, getters
, actions
, mutations
,在每个组件中可以通过 this.$store
打印出来看看。
开始使用
定义状态
export default new Vuex.Store({ state: { count: 1 // state 中定义响应式的数据 } })
使用状态 :在 store 的 state
中定义的状态 count
,在组件中可以使用 this.$store.state.count
获取。
定义 mutations
在 store 的 mutations
中添加对应的方法
export default new Vuex.Store({ state: { count: 1 // state 中定义响应式的数据 }, mutations: { addTen (state, num) { state.count = state.count + num } }, actions: { } })
提交 mutations
组件中通过 commit
提交 mutations
去修改 state
中的状态
this.$store.commit('addTen', 10)
定义 actions
在 store 的 actions
中添加对应的方法
export default new Vuex.Store({ state: { count: 1 }, mutations: { addTen (state, num) { // 第一个参数是状态,第二个是传入的参数 state.count = state.count + num } }, actions: { minusTen ({commit}, num) { // 第一个参数是 store 实例,第二个是传入的参数 setTimeout(() => { commit('addTen', num) }, 1000) } } })
派发动作
组件中可以使用 dispatch
派发一个动作,来触发 actions
中的方法, actions
可以异步的提交 mutations
去修改 state
中的状态
this.$store.dispatch('minusTen', 10)
actions
主要是复用,封装代码,处理异步,请求接口等等,真正修改状态放到了mutations
中处理
定义 getters
在 store 的 getters
中添加对应的方法
export default new Vuex.Store({ state: { count: 1, person: { name: '张三' } }, getters: { getName (state) { // getters 是同步的 return state.person.name } } })
使用 getters
this.$store.getters.getName
getters
定义的方法相当于计算属性,相当于定义在computed
一样,有缓存,依赖改变会重新计算。
组件代码演示
<template> <div class="hello"> <h1>{{ this.$store.state.count }}</h1> <h1>{{ this.$store.getters.getName }}</h1> <button @click="syncAdd">同步加 10</button> <button @click="asyncAdd">异步加 10</button> </div> </template> <script> export default { methods: { syncAdd () { this.$store.commit('addTen', 10) }, asyncAdd () { this.$store.dispatch('minusTen', 10) } } } </script>
简写
上面的写法都是在 this.$store
中获取属性或方法进行操作。
this.$store.state.count this.$store.getters.getName this.$store.commit('addTen', 10) this.$store.dispatch('minusTen', 10)
但是这些操作写起来比较繁琐,每次都要写 this.$store
,为了简写,所以 vuex 提供了一些映射的方法,直接导入到组件中就可以使用了。
<template> <div class="hello"> <h1>{{ count }}</h1> <h1>{{ getName }}</h1> <button @click="syncAdd">同步加 10</button> <button @click="asyncAdd">异步加 10</button> </div> </template> <script> import {mapActions, mapState, mapMutations, mapGetters} from 'vuex' export default { computed: { ...mapState(['count']), ...mapGetters(['getName']) }, methods: { syncAdd () { this.addTen(10) }, asyncAdd () { this.minusTen(10) }, ...mapActions(['minusTen']), ...mapMutations(['addTen']) } } </script>
有一点需要说明的是,使用扩展运算符,表示这些方法返回的都是对象, mapState
和 mapGetters
需要定义在计算属性中,因为他们定义的数据是响应式的。而 mapActions
和 mapMutations
需要定义在 methods 中。
拆分模块
状态是可以分层的,当一个项目维护的状态太多,可以拆分成单独的模块,在定义 store 中有个 modules
属性,里面可以定义单独的模块。
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ modules: { 'page1': { namespaced: true, state: { count: 1, person: { name: '张三' } }, mutations: { addTen (state, num) { state.count = state.count + num } }, actions: { minusTen ({commit}) { setTimeout(() => { commit('addTen', 10) }, 1000) } }, getters: { getName (state) { return state.person.name } } } } })
在组件中这样用
<template> <div class="hello"> <h1>{{ count }}</h1> <h1>{{ getName }}</h1> <button @click="syncAdd">同步加 10</button> <button @click="asyncAdd">异步加 10</button> </div> </template> <script> import {mapActions, mapState, mapMutations, mapGetters} from 'vuex' export default { computed: { ...mapState('page1', ['count']), ...mapGetters('page1', ['getName']) }, methods: { syncAdd () { this.addTen(10) }, asyncAdd () { this.minusTen(10) }, ...mapActions('page1', ['minusTen']), ...mapMutations('page1', ['addTen']) } } </script>
每个方法都传了两个参数,第一个参数指定命名空间,第二个参数是对应的属性,为了进一步简写,可以通过帮助函数指定命名空间,指定当前组件在使用的模块。
<template> <div class="hello"> <h1>{{ count }}</h1> <h1>{{ getName }}</h1> <button @click="syncAdd">同步加 10</button> <button @click="asyncAdd">异步加 10</button> </div> </template> <script> import { createNamespacedHelpers } from 'vuex' // 创建帮助函数指定命令空间 let { mapActions, mapState, mapMutations, mapGetters } = createNamespacedHelpers('page1') export default { computed: { ...mapState(['count']), ...mapGetters(['getName']) }, methods: { syncAdd () { this.addTen(10) }, asyncAdd () { this.minusTen(10) }, ...mapActions(['minusTen']), ...mapMutations(['addTen']) } } </script>
不使用简写
this.$store.getters['page1/getName'] this.$store.state.page1.count this.$store.commit('page1/addTen', 10) this.$store.dispatch('page1/minusTen', 10)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

上一篇: 简单入门 Buffer
下一篇: 不要相信一个熬夜的人说的每一句话
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论