沃梦达 / IT编程 / 前端开发 / 正文

Vuex的五个核心概念

文章目录五个核心概念1. state2. Getters的使用3 Mutations3.1 基本使用3.2 响应规则3.3 常量类型3.4 同步函数4. Action4.1 使用Promise5 Moudle6 项目结构五个核心概念const store=new Vuex.Store({state:{},mu...

文章目录

  • 五个核心概念
    • 1. state
    • 2. Getters的使用
    • 3 Mutations
      • 3.1 基本使用
      • 3.2 响应规则
      • 3.3 常量类型
      • 3.4 同步函数
    • 4. Action
      • 4.1 使用Promise
    • 5 Moudle
    • 6 项目结构

五个核心概念

const store=new Vuex.Store({
  state:{},
  mutations:{},
  actions:{},
  getters:{},
  modules:{}
})

? 以上为五个核心概念的内容,接下来我们一一介绍:

? 首先贴出一张图以备我们后面使用:

1. state

? 首先我们需要弄清楚的是state的功能,我们前面提到state是用来放置我们所有状态的属性。

? 在Vuex中提出了单一状态树的概念,也就是单一数据源的意思。意思就是我们全局只有一个store实例,也就是是我们只有一个管家的角色,这样一来统一了数据源,不会造成一些不必要的冲突。

单一状态树让我们能够直接地定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用状态的快照。

? 我们可以看一下State的定义和使用

定义:

 state:{
    counter:0
  },

使用(可以在模板中使用也可以在计算属性中使用):

<p>{{$store.state.counter}}</p>

2. Getters的使用

? 这里的getters实际上类似于我们组件中的计算属性,通常用于返回我们某个状态改变后的状态。

? 并且我们定义的getters函数可以包含一个state的参数,这个参数的含义就是我们的store下的state状态

? 我们下面可以模拟一个场景:有一组学生我们需要获取其大于20岁的人以及个数。

student状态:

student:[
      {id:1,name:'a',age:12},
      {id:2,name:'b',age:21},
      {id:3,name:'c',age:34},
      {id:4,name:'d',age:26},
    ]

getters:

 getters:{
    more20person(state){
      return state.student.filter((s) => {
        return s.age>20
      })
    }
  },

? 其实除此之外我们还可以为其传参,比如我们现在想让年不是age,而是我们给定的值。那么我们就需要返回一个函数类型的返回值,给返回的函数设定参数。

moreageperson(state){
      return function (tt) { 
        console.log(tt);
        return state.student.filter((s) =>s.age>tt) 
     }
    },

使用方法:

    <p>{{$store.getters.moreageperson(10)}}</p>

3 Mutations

? 通过文中一开始贴的图我们看出Vuex的store中状态更新的唯一方式就是通过提交Mutation的方式来进行,因为我么这里需要DevTools进行追踪我们状态的更新情况。

因此我们可以知道Mutation常常用于操作变更状态数据。

3.1 基本使用

? 一个Mutation主要包括两部分的内容:

  1. 字符串的事件类型
  2. 一个回调函数,其中可以包含两个参数一个是state,另一个是我们自定义传入的参数。

这是一个Mutation的实例代码:

mutations:{
    increment(state){
      state.counter++
    }
  }

使用方法(在组件中直接通过store的commit方法调用):

this.$store.commit('increment')

? 接下来可以看看它的传参,参数称为Mutaions的载荷(payload).

? 参数的方式有两种,一种是直接进行传入,这种方式的缺点是只能传入一个参数

? 第二种是传入一个对象,这就实现了定义多个参数的功能。

3.2 响应规则

通过上面的一些代码我们会发现Vuex中的state数据是响应式的,因为他们在刚一定义时就被加入到Vue的响应式系统中了,因此当我们改变了状态数据之后,我们数据也可以做到响应式了。

但是我们还需要遵守一些规则:

  1. 在刚开始初始化时就将state中的属性定义好
  2. 如果后期想添加或者删除属性,不能通过es的基本语法

我们需要使用Vue.set的方式给其赋值,使用Vue.delete的方式给其删除属性。

我们可以看一下以下的例子:

原数据:

 info:{name:'cc',age:13},

使用普通方式增加属性

updatastate(state){
      state.info['address']='北京'
}

这时运行代码,我们发现在devTools中数据确实更新了,但是我们用在界面上的数据并没有更新。

当我们使用第二种方式时:

   updatastate(state){
      // state.info['address']='北京'
      Vue.set(state.info,'address','北京')
    }

这时我们发现数据和界面都更新了。

这说明我们使用Vue的set方法内部可以将我们增添的属性加入它的响应式系统中

3.3 常量类型

? 在mutation中, 我们定义了很多事件类型(也就是其中的方法名称),当我们的项目增大时, Vuex管理的状态越来越多, 需要更新状态的情况越来越多, 那么意味着Mutation中的方法越来越多.

? 方法过多, 使用者需要花费大量的经历去记住这些方法, 甚至是多个文件间来回切换, 查看方法名称, 甚至如果不是复制的时候, 可能还会出现写错的情况.

? 因此我们使用常量替代Mutation事件的类型(上文提到的type),我们可以将这些常量放在一个单独的文件中, 方便管理以及让整个app所有的事件类型一目了然.

具体做法:

  1. 创建一个专门终于储存常量type名的文件,并导出
  2. 使用es6函数命名方式导出进行使用
[常量](state,payload){

}

3.4 同步函数

? 通常情况下, Vuex要求我们Mutation中的方法必须是同步方法.

? 我们可以看上面的图,会发现Vuex主要将后端的异步操作都交给了Action处理,异步操作结束后再交给Mutation。最主要的是在Mutation这一环节有一个DevTools追踪记录环节。

? 因而如果我们在这里使用异步的耗时操作DecTools是追踪不到我们我们的记录的。

? 我们可以在Mutation中加一个异步操作测试以下DevTools会不会追踪到我们数据的改变。

就用我们上文的改变属性操作:

 updatastate(state){
        setTimeout(() => {
          Vue.set(state.info,'address','北京')          
        }, 1000);
      }
  },

这时我们发现DevTools是没有这条属性增加的记录的。

因此我们得出结论:不要再Mutation中执行任何异步的操作。

4. Action

? 经过文上对Mutaion同步函数的介绍你是否对Action有一定的理解,对,就是Vuex为我们专门用于异步耗时操作的一个环节。之后再取将我们数据提交到Mutation。

? Action中的函数是可以有两个参数的,一个是context,一个是我们的payload,payload参数和Mutation的参数使用是一样的。

? 其中context是指上下文,代表了我们的store对象。

这里我们依然使用上文的实例来进行对增添属性的异步操作:

actions: {
    undatadata(context) {
      setTimeout(() => {
        context.commit('updatastate')
      }, 2000);
    } 
  },

使用dispeach进行调用事件:

<button @click="$store.dispatch('undatadata')">updata</button>

这时我们发现再devtools监听到了数据的变化。

4.1 使用Promise

如果我们这里增加需求,当异步操作完成之后来提醒我们异步操作完成。

这里有两种方式来处理,一种是回调函数的形式,一种就是promise:

我们这里直接来看promise:

 actions: {
    undatadata(context) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          context.commit('updatastate');
          resolve('改变成功')
        }, 2000);
      });
    }
  },

使用:

 datachange(){
      this.$store.dispatch('undatadata').then((result) => {
        console.log(result);
      }).catch((err) => {
        
      });
    }

这里我们使undatadata方法返回一个Promise对象,然后世界this.$store.dispatch(‘方法名’)就可以直接拿到它的返回值,我们就可以直接在这里进行操作。

5 Moudle

? Module是模块的意思, 为什么在Vuex中我们要使用模块呢? Vue使用单一状态树,那么也意味着很多状态都会交给Vuex来管理。当应用变得非常复杂时,store对象就有可能变得相当臃肿.

? 为了解决这个问题, Vuex允许我们将store分割成模块(Module), 而每个模块拥有自己的state、mutation、action、getters等

这时从官网直接copy下来的代码:

const moduleA = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态

? 定义了两个模块AB,直接再store的moudles中进行注册

? 但是再使用时我们需要注意要直接再store.state.模块名.内容中调用,并不是再moudles中,这时vuex将moudles里面的内容放入到store的state中了。

? 需要注意的是我们moudles中的Mutation也是和普通的调用方法一样直接从store中调用的,注意不要于其他地方的mutation重名。但是模块里面Mutation中的参数state是模快内部的状态数据。

? 同样,对于模块内部的 action,局部状态通过 context.state 暴露出来,根节点状态则为 context.rootState,具体我们可以打印context的内容来根据我们需求进行变换。这里的context对应的是本模块下的内容,root层需要其他的方法调用

? 对于模块内部的 getter,根节点状态会作为第三个参数暴露出来:state, getters, rootState。

6 项目结构

再开发中我们的vuex内容一般不会写在一个js文件中,回具体的分成不同文件结构,这样让我们的代码更加清晰。

来自官网

├── index.html
├── main.js
├── api
│   └── ... # 抽取出API请求
├── components
│   ├── App.vue
│   └── ...
└── store
    ├── index.js          # 我们组装模块并导出 store 的地方
    ├── actions.js        # 根级别的 action
    ├── mutations.js      # 根级别的 mutation
    └── modules
        ├── cart.js       # 购物车模块
        └── products.js   # 产品模块

本文标题为:Vuex的五个核心概念