老规矩先安装
在看下面内容之前 你应该大概的看了一边vuex官方的文档对vuex有个大概对了解
首先
vuex 是什么?
vuex 是属于vue中的什么,它在项目中扮演着一个什么样的角色,起到什么作用,在项目中我是否要用到vuex。
官方文档对vuex的解读是:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。
如果你是在开发一个大型的应用程序,组件与组件之间,兄弟组件之间,或者说多层嵌套组件之间,你是无法传递数据的。子父组件之间,也只是说通过事件保持数据的一致性,也是很繁琐的,会变得很不好管理。而vuex就是为了解决这样的问题,把组件的共享状态抽取出来,以一个全局单例模式管理。组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为,而且代码将会变得更结构化且易维护。
新建一个最简单的store
store.js
- import Vue from 'vue'
- import Vuex from 'vuex'
- Vue.use(Vuex)
- export default new Vuex.Store({
- state: {
- count: 0,
- me: {
- name: 'huangenai',
- age: 22,
- sex: '女'
- },
list: [{name: 'hea', age: 22}, {name: 'cpq', age: 23}]
- },
- mutations: {
- increment (state) {
- state.count++
- }
- }
- })
main.js
- import store from './store.js'
- new Vue({
- el: '#app',
- router,
- store,//加这个
- components: { App },
- template: '<App/>'
- })
State
驱动应用的数据源,组件之间共享的状态。
上面代码中的 count 就是一个共享的数据,me 也是一个共享的数据对象。
在组件中获得state 中的count
newvue.vue
- <template>
- <div>
- new vue page
- <p>{{count}}</p>
- </div>
- </template>
-
- <script>
- export default {
- name: 'newvue',
- data () {
- return {
- }
- },
- computed: {
- count () {
- return this.$store.state.count
- }
- }
- }
- </script>
-
- <style scoped>
- </style>
为什么要写在computed 里面呢,而不是写在data里面,因为当state.count 变化的时候, 都会重新求取计算属性,并且触发更新相关联的 DOM,如果你不理解可以先去看看computed
当一个组件要引用到多个状态的时候 ,一个个写是不是很累。不用担心,我们有mapState
辅助函数帮助我们生成计算属性。
在组件中引用
- import { mapState } from 'vuex'
- <template>
- <div>
- <p>{{count}}</p>
- <p>{{countPlusLocalState}}</p>
- <p>sex: {{sex}}</p>
- <p>age: {{myAge}}</p>
- <p>name: {{name}}</p>
- </div>
- </template>
-
- <script>
- import { mapState } from 'vuex'
- export default {
- name: 'newvue',
- data () {
- return {
- localCount: 1
- }
- },
- computed: {
- ...mapState({
- // 箭头函数可使代码更简练
- sex: state => state.me.sex,
- myAge: state => state.me.age,
- name: state => state.me.name,
- // 传字符串参数 'age' 等同于 `state => state.age`
- count: 'count',
- // 为了能够使用 `this` 获取局部状态,必须使用常规函数
- countPlusLocalState (state) {
- return state.count + this.localCount
- }
- })
- }
- }
- </script>
-
- <style scoped>
- </style>
假设computed 里面还有别的数据,因为mapstate返回来的是一个对象所以我们这样写可以将数据混入
computed: {
localComputed () {
Mutation
你说你想修改state的值,this.$store.state.count = 1 这样可不可以 no no no.... 所以就有了Mutation。
切记Mutation 必须是同步函数!!!
想要修改 Vuex 的 store 中的状态的唯一方法是提交 mutation。
在上面代码我们新建一个store里面下的 有一个increment,就可以实现修改state里面的count
- export default new Vuex.Store({
- state: {
- count: 0
- },
- mutations: {
- increment (state) {
- state.count ++
- }
- }
- })
那么如何调用increment呢??
调用 this.$store.commit(type) 类型叫increment
的 mutation。
- this.$store.commit('increment')
我们还可以传入参数
store.commit('increment', 10)
传入一个对象
mutations: {
increment (state, data) {
state.count += data.count
}
}
store.commit('increment', {
count: 10
})
mutations可以修改store中的状态,但是并不是说随随便便修改的,比如说??状态是对象的时候,你突然重新赋值过去一个新对象,原来的属性没了,真怎么行。
Vuex 的 store 中的状态是响应式的,那么当我们变更状态时,监视状态的 Vue 组件也会自动更新。
比如 上面代码的 state 内有个对象me 我可以新增删除里面的属性吗,怎么操作呢。
最好就是一开始就定义好所有的属性。
如果你非要新增属性,也提供了方法。
1. Vue.set(me, 'height','156cm')
2. state.me = { ...state.me, height: '156cm' }
store.js
- ...
- mutations: {
- increment (state) {
- state.count++
- },
- setWeight (state) {
- Vue.set(state.me, 'weight', '45kg')
- },
- setHeight (state) {
- state.me = { ...state.me, height: '156cm' }
- }
- }
newvue.vue 中调用
- ...
methods: { - setWeight () {
- this.$store.commit('setWeight')
- alert(JSON.stringify(this.$store.state.me))
- },
- setHeight () {
- this.$store.commit('setHeight')
- alert(JSON.stringify(this.$store.state.me))
- }
- }
当mutations中的类型多了起来,我们在组件中要commit 某一个类型 还要去找 再复制过来 是不是很不好管理。
所以我们可以使用常量替代 mutation 事件类型,新建一个
- export const SET_WEIGHT = 'SET_WEIGHT'
- export const SET_HEIGHT = 'SET_HEIGHT'
store.js
- import * as types from './metations-types'
- ...
- mutations: {
- increment (state) {
- state.count++
- },
- [types.SET_WEIGHT] (state) {
- Vue.set(state.me, 'weight', '45kg')
- },
- [types.SET_HEIGHT] (state) {
- state.me = { ...state.me, height: '156cm' }
- }
- }
newvue.vue
- ....
- methods: {
- setWeight () {
- this.$store.commit(types.SET_WEIGHT)
- alert(JSON.stringify(this.$store.state.me))
- },
- setHeight () {
- this.$store.commit(types.SET_HEIGHT)
- alert(JSON.stringify(this.$store.state.me))
- }
- }
state中有mapState, Mutations中也有mapMutations
使用 mapMutations
辅助函数将组件中的 methods 映射为 this.$store.commit
调用
newvue.vue
先引用
import { mapMutations } from 'vuex'
- ...
- setWeight () {
- this.$store.commit(types.SET_WEIGHT)
- alert(JSON.stringify(this.$store.state.me))
- },
- setHeight () {
- this.$store.commit(types.SET_HEIGHT)
- alert(JSON.stringify(this.$store.state.me))
- },
- ...mapMutations([
- 'increment'
- // 将 `this.increment()` 映射为 this.$store.commit('increment')`
- ])
- }
getter
getter 又是什么 ,在store中。什么时候用到他。
上述我们可以用 this.$store.state.count 能拿到 store的state ,而getter 则是拿store中的计算属性。
比如store 中的state 中的list
在项目中我们有多个组件需要通过过滤拿到list中 age 大于等于22的对象,如果没有getter 我们需要在每个组件中都要定义一个函数过滤好在返回值,或者抽出来一个公共的方法哪个组件需要的时候就导入这个方法,再进行调用,也是很麻烦的一件事。
在这里我们可以用到store 里的getter,并通过属性访问获得过滤后的数据
store.js
- export default new Vuex.Store({
- state: {
- ...
- list: [{name: 'hea', age: 22}, {name: 'cpq', age: 23}]
- },
- mutations: {
- ...
- },
- getters: {
- ageFilter: state => {
- return state.list.filter(item => item.age>=23)
- }
- }
- })
newvue.vue
- ....
- computed: {
- list () {
- return this.$store.getters.ageFilter
- }
- }
在getter中,Getter 也可以接受其他 getter 作为第二个参数。
例子
- ...
- getters: {
- ageFilter: state => {
- return state.list.filter(item => item.age >= 23)
- },
- listCount (state,getters){
- return getters.ageFilter.length
- }
- }
newvue.vue中调用
- ...
- computed: {
- ...
- listCount () {
- return this.$store.getters.listCount
- }
- }
通过方法访问,让getter返回一个函数,我们可以传值过去
store.js
- ...
- getters: {
- ....
- getName: (state) => (name) => {
- return state.list.find(item => item.name === name)
- }
- }
newvue.vue
- ....
computed: {
.... - listbyName () {
- return this.$store.getters.getName('cpq')
- }
- }
getter 有mapGetters 辅助函数,将 store 中的 getter 映射到局部计算属性
newvue.vue
- import { mapGetters } from 'vuex'
- computed: {
- ....
- // listCount () {
- // return this.$store.getters.listCount
- // },
- ...mapGetters([
- 'listCount'
- ])
- }
在组件中,什么时候通过getter拿到store 状态,什么时候 直接拿state 想必都清楚了。
Action
其实跟上述的mutation很相似。
但是他不是直接修改state,在上面mutation说过,必须是同步函数。而Action则可以包含任意异步函数,action 是通过提交 mutation,而修改state。
store.js
- export default new Vuex.Store({
- state: {
- ...
- },
- mutations: {
- ...
- },
- getters: {
- ...
- },
- actions: {
- setWeight ({commit}) {
- commit(types.SET_WEIGHT)
- }
- }
Action 通过 this.$store.dispatch
方法触发
newvue.vue
- ...
- methods: {
- ...
- setWeight () {
- this.$store.dispatch('setWeight')
- }
- }
同样action 也支持传参数
action.js
- export default new Vuex.Store({
- state: {
- count: 0,
- ...
- },
- mutations: {
- increment (state,count) {
- state.count = count
- },
- ...
- },
- getters: {
- ...
- },
- actions: {
- ...
- setCount ({commit},data) {
- commit('increment',data.count)
- }
- }
- })
newvue.vue
- methods: {
- ...
- setCount () {
- this.$store.dispatch('setCount', {count: 123})
} - }
为什么要action 直接用mutation岂不更方便,为什么要通过action,又多了一步
因为mutation只是同步函数啊,在很多情况下我们要执行异步操作的。
action可以包含异步函数。
我们假设一个登录的功能,在action中支持异步函数,在mutation只能是同步函数,所以要用到action
- import api from '../api'
- ...
- actions: {
- login ({commit}, payload) => {
- return new Promise((resolve, reject) => {
- api.login(payload, userToken => {
- if (userToken && userToken.accessToken) {
- commit(types.LOGIN, userToken)
- resolve(userToken)
- } else {
- reject()
- }
- })
- })
- }
调用
- this.$store.dispatch('login', {username, password}).then(
- (res) => {
-
- }).catch()
同样action也有辅助函数 mapActions
- import { mapActions } from 'vuex'
- export default {
- // ...
- methods: {
- ...mapActions([
- 'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`
- }
- }
你还可以action中相互调用
- actions: {
- ...
- setCountA ({commit},count) {
- commit('increment', count)
- },
- setCountB ({commit},data) {
- dispatch('setCountA',data.count)
- }
- }
此随笔乃本人学习工作记录,如有疑问欢迎在下面评论,转载请标明出处。
如果对您有帮助请动动鼠标右下方给我来个赞,您的支持是我最大的动力。