1

出现原因

vuex出现之前,共享数据的难题:

1、书写特别繁琐
2、依赖极其混乱
3、无谓的重新渲染

vuex出现之后

专门解决共享数据问题,解决思路是把数据提升到最顶层,不过它使用了一些特殊的技巧,让组件的依赖更加清晰,当数据发生变化时,仅渲染依赖数据的组件

好处

  1. 集中管理(共享)数据,易于开发和维护
  2. 高效地实现组件之间的数据共享,提高开发效率
  3. 存储在vuex中的数据是响应式的,数据改变,使用到的地方会自动实时更新

基本使用

第一步:安装依赖包

npm i vuex --save

第二步:导入

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

第三步:创建store对象

const store = new Vuex.store({
    state: {count:0}
});

第四步:把store实例挂载到Vue根实例中,进行关联

new Vue({
    el: "#app",
    render: h => h(app),
    store,
    router
})
安装完成后,会在vue实例中添加一个共有属性:$store
原理就是通过 Vue.prototype.$store 添加

五大核心概念

State (状态仓库)

用于存储所有共享数据
组件使用时,要在 computed 声明

组件中访问state中共享数据的方式

1、第一种直接访问(不推荐)

// 非模块
this.$store.state.全局数据名称

// 模块
this.$store.state.模块名.全局数据名称

2、第二种使用辅助函数(推荐)

1、从 vuex 按需导入 mapState 辅助函数
import {mapState} from 'vuex'

2、将当前组件需要的全局数据,映射为当前组件的computed计算属性
// 非模块写法
computed: {
    ...mapState(['count'])
}
或者
computed: {
    ...mapState({
         count: state => state.count,  // 第一种
         count: 'count'  // 第二种
    })
}

// 模块
computed: {
    ...mapState({
         count: state => state.模块名.count
    })
}
注意事项:
官方推荐我们将vuex的state属性绑定到computed,为何不可以绑定到data里面呢?

错觉:data中的内容只会在 created 钩子触发前初始化一次,之后需要通过js修改data里面的属性值,页面才响应式改变,那么把state里的数据绑定到data中,state中数据改变,data中对应的数据也会跟着改变不对吗?

回答:上面说法有一半对,一半错。到底错在哪呢?

错在:如果state里面的状态值类型是数值、布尔、字符串基础数据类型的话,那么赋值就是值传递,如下

let a = 12;
let b = a;
a = 20;

alert(a) //20
alert(b) //12

这样你明白了吧,如果把state中状态传递给data,那么当state中状态改变后,因为不是引用传递,data中对应属性值不会改变

总结:
data是在create钩子触发前初始化一次
data中由于没有依赖跟踪,所以必须引用传递才可以做到响应式

Getter (状态处理、包装)

用于对 state 中状态进行包装,不会对 state 中原数据有任何修改
类似于 computed 计算属性
state 中数据发生变化, getter 中数据也发生变化 响应式
组件使用时,要在 computed 声明

定义

// getter里面放的也是函数
state: {count:0},
getters: {
    doneTodos: state => {
      return '当前最新数量' + state.count + '个'
    }
}

使用

// 第一种方式
this.$store.getters.名称

// 第二种方式
1、从 vuex 中按需导入 mapGetters 辅助函数
import {mapGetters} from vuex
2、将导入的 getter 函数,映射为当前组件的 computed 计算属性
computed: {
    ...mapGetters(['doneTodos'])
}

Mutation (修改状态)

vuex 不允许直接修改 state 中数据,必须使用 Mutation 来修改
Mutation 中定义的函数必须是同步函数,不能是异步的

定义函数

// 定义的函数接受2个参数:
1、state
2、传参

mutations: {
  increment (state, params) {
     // 变更状态
     state.count++
  }
}

组件中使用

// 第一种方式
this.$store.commit('increment', 12);

// 第二种方式 (当成方法使用,更加简单方便)
1、从 vuex 中按需导入 mapMutation 辅助函数
import {mapMutations} from vuex
2、将导入的 mutation 函数,映射为当前组件的methods函数
methods: {
    ...mapMutations(['increment'])
}
3、调用
this.increment(参数);

模块时,该如何使用呢?

// 第一种方式
this.$store.commit('base/increment', 12);

// 第二种方式
1、从 vuex 中按需导入 mapMutation 辅助函数
import {mapMutations} from vuex
2、将导入的 mutation 函数,映射为当前组件的methods函数
methods: {
    ...mapMutations(['base/increment']),
    ...mapMutations('base', ['increment'])
}
3、调用
this['base/increment'](4)
this.increment(13)

Action (异步操作)

与 Mutation 类似,唯一区别是:
mutation 是同步函数,唯一修改 state 状态值的方法
action 是异步函数,但不能修改 state 状态值

定义函数

// 定义的函数接受2个参数:
1、context
2、传参

actions: {
  incrementAsync (context, params) {
    setTimeout(() => {
      context.commit('increment', params)
    }, 1000)
  }
}

组件中使用

// 第一种方式
this.$store.dispatch('incrementAsync', 12);

// 第二种方式 (当成方法使用,更加简单方便)
1、从 vuex 中按需导入 mapMutation 辅助函数
import { mapActions } from vuex
2、将导入的 action 函数,映射为当前组件的methods函数
methods: {
    ...mapActions(['incrementAsync'])
}
3、调用
this.incrementAsync(参数);

模块时,该如何使用呢?

// 第一种方式
this.$store.dispatch('base/incrementAsync', 12);

// 第二种方式
1、从 vuex 中按需导入 mapMutation 辅助函数
import {mapActions} from vuex
2、将导入的 action 函数,映射为当前组件的methods函数
methods: {
    ...mapActions(['base/incrementAsync']),
    ...mapActions('base', ['incrementAsync'])
}
3、调用
this['base/incrementAsync'](4)
this.incrementAsync(13)

104828720
1.4k 声望222 粉丝

编程其实很枯燥,所以一定要有追求。