vuex-core concept|Youth training camp notes


theme: condensed-night-purple

highlight: a11y-dark

This is the 9th day of my participation in the "Fifth Youth Training Camp" Companion Notes Creation Activity

Vuex has several core concepts:

  • State: Save the shared state and store state-related information
  • Getters: similar to computed properties
  • Mutation: status update
  • Action: Perform an asynchronous operation
  • Module: Divide modules and save related data for different modules

State single state tree

There is an auxiliary function of mapState in the STATE attribute

State: Save the shared state and store state-related information

Build only one store in a project

Vuex proposes to use a single state tree , what is a single state tree? The English name is Single Source of Truth, which can also be translated into a single data source .

If your state information is stored in multiple Store objects, subsequent management and maintenance will become particularly difficult. So Vuex also uses a single state tree to manage all states at the application level.

A single state tree allows us to find a fragment of a certain state in the most direct way, and it can also be managed and maintained very conveniently in the subsequent maintenance and debugging process.

Getters are similar to computed properties and are used when you need to get some mutated state from the store

The difference from mutations should be that it is used instead of changing the original appearance

The operations defined in the mutation will change the property values ​​in the state, but the methods defined in the getter only process the data, and do not change the property values ​​in the state.

Getters cannot pass parameters by default. If you want to pass parameters, you can only let getters return another function```js

{ { $store.getters.powerCounter }}

{ { $store.getters.more20stu }}

{ { $store.getters.more20stuLength }}

{ { $store.getters.moreAgeStu(18) }}

getters: { powerCounter (state) { return state.counter * state.counter }, more20stu(state) { return state.students.filter( s => s.age >= 20) }, // getters也可以作为参数转入 // 但getters里的方法只能接收两个参数:state和getters more20stuLength(state, getters) { return getters.more20stu.length }, // 想要自己给定比较的age,可以返回一个函数,将参数传入 moreAgeStu(state) { return age => { return state.students.filter( s => s.age > age) } } }, ```

Mutation 状态更新

Vuex的store状态的更新唯一方式:提交Mutation

Mutation主要包括两部分:

  • 字符串的事件类型(type) (例如 increment)
  • 一个回调函数(handler),该回调函数的第一个参数就是state。

```js // mutation的定义方式: mutations: { // 方法 默认参数state 自动传入state increment(state) { state.counter++ } },

// 通过mutation更新 // 在app里 methods: { addition() { this.$store.commit("increment") // 使用commit方法,传入方法名 // 跟踪每一次的提交的状态 } }, ```

Mutation传递参数

在通过mutation更新数据的时候, 有可能我们希望携带一些额外的参数

参数被称为是mutation的载荷(Payload)

但是如果参数不是一个呢? 比如我们有很多参数需要传递. 这个时候, 我们通常会以对象的形式传递, 也就是payload是一个对象. 这个时候可以再从对象中取出相关的信息. ```js // Mutation中的代码: mutations: { incrementCounter(state, count) { // mutation的使用与事件处理函数非常相似,都具有类型和回调函数 // (类似methods,不过获取state中的变量不是this.变量名,而是state.变量名)。 state.counter += count }, addStudent(state, stu) { state.students.push(stu) } },

// 在app里的代码:

methods: { addCount(count) { this.$store.commit("incrementCounter", count) }, addStudent() { // 有多个参数,通过对象同一传递 // payload:负载 参数被称为是mutation的载荷(Payload) const stu = { id : 104, name : "alban", age : 26} this.$store.commit("addStudent", stu) } } ```

Mutation提交风格

上面的通过commit进行提交是一种普通的方式。 Vue还提供了另外一种风格, 它是一个包含type属性的对象 ```js addCount(count) { // 1. 普通的提交风格 // 提交的只是值 // this.$store.commit("incrementCounter", count)

// 2. 特殊的提交风格
  // 将整个对象提交过去
  this.$store.commit({
    type : "incrementCounter",  // type就是mutations里的方法名
    count   // counter : counter  ES6
  })
}

```

Mutation中的处理方式是将整个commit的对象作为payload使用, 所以代码没有改变, 依然如下 ```js incrementCounter(state, payload) { // mutation的使用与事件处理函数非常相似,都具有类型和回调函数 // (类似methods,不过获取state中的变量不是this.变量名,而是state.变量名)。

// 普通提交
  // console.log(count);
  // state.counter += count

  // 特殊提交
  // 此时count可以写成payload
  console.log(payload);
  state.counter += payload.count
}

```

Mutation响应规则

前排提醒,本节讲述的方法在Vue3已经废弃,Vue3可以直接在mutations正常赋值

Vuex的store中的state是响应式的, 当state中的数据发生改变时, Vue组件会自动更新.

这就要求我们必须遵守一些Vuex对应的规则: 提前在store中初始化好所需的属性.

When adding new properties to objects in the state , use the following methods: - Method 1: Use Vue.set(obj, 'newProp', 123) - Method 2: Use new objects to reassign old objects

```js

------------App component --Mutations use --info object whether the content is responsive --------------

{ { $store.state.info }}

updataInfo() { this.$store.commit("updataInfo") }
mutations代码   
    updataInfo(state) {
  // state.info.name = "abc"

  // 要添加属性
  // 这种方法不是响应式的
  // state.info['address'] = '多伦多'
  // 
  Vue.set(state.info, 'address', '多伦多')

  // 删除属性
  // delete state.info.age
  Vue.delete(state.info, 'age')
}

```

The initialization attribute of each object in the state has a watcher , and the attribute defined at the beginning will be added to the responsive system of vue, and then the change of the attribute will be observed through DEP->[watcher], (each attribute corresponds to a dep, dep corresponds to many watchers, and dep stores the collection of wathers. Internal responsive system: dep monitors changes in attributes - observer mode. After data changes, see which places need to be refreshed according to data changes. The interface dep has an array, which contains many watchers. , notify the corresponding watcher to change the page)

The attributes defined at the beginning of the state will be added to the responsive system, and the responsive system will monitor the changes of the attributes. When the attributes change, it will notify all the places where the attributes are used in the interface, so that the interface will be refreshed

Each attribute has its own dependency array, which contains different watchers, and the watcher corresponds to each place in the view that calls this attribute

The attributes added later have not been added to the responsive system, so they cannot respond, and the interface has not been refreshed. To implement responsiveness, you need to use Vue.set(the object of the attribute to be added, "attribute name", attribute value) to delete it with Vue.delete( object of properties to delete, "property_name")

Mutation constant type

concept

问题: 在mutation中, 我们定义了很多事件类型(也就是其中的方法名称). 当我们的项目增大时, Vuex管理的状态越来越多, 需要更新状态的情况越来越多, 那么意味着Mutation中的方法越来越多. 方法过多, 使用者需要花费大量的经历去记住这些方法, 甚至是多个文件间来回切换, 查看方法名称, 甚至如果不是复制的时候, 可能还会出现写错的情况.

如何避免? 一种很常见的方案就是使用常量替代Mutation事件的类型. 将这些常量放在一个单独的文件中, 方便管理以及让整个app所有的事件类型一目了然.

具体怎么做? 创建一个文件: mutation-types.js, 并且在其中定义我们的常量. 定义常量时, 我们可以使用ES2015中的风格, 使用一个常量来作为函数的名称.

代码

```JS -----mutation-types.js export const INCREMENT = 'increment' 这样导出时要注意,导入时要用对象(普通导出)

-----index.js // '函数名字'{} //在对象中可以这样定义方法 // 在ES6中,把属性名用[ ]括起来,则括号中就可以引用提前定义的变量。 INCREMENT { state.counter ++ },

-----app.vue import HelloWorld from './components/HelloWorld.vue'; // 这种方式只能是export default导出 import { INCREMENT, }from './store/mutations-types' // 普通导出要这样导入 this.$store.commit(INCREMENT) ```

Mutation同步函数

Vuex要求我们Mutation中的方法必须是同步方法

在mutations里进行异步操作,看起来是修改了state, 但是devtools无法跟踪该步操作,使得记录的state数据是操作之前的,导致出现错误

Action

总结:state(存放数据),getter(处理数据), mutations(修改数据), actions(接收异步数据)

概念

Action类似于Mutation, 但是是用来代替Mutation进行异步操作的.

异步操作要在actions里进行,然后提交commit到mutataions,在mutations里对state进行修改 在app里,需要dispatch到actions, actions可以传递参数payload,它的第一个参数为context,可以理解为store

context是和store对象具有相同方法和属性的对象,可以通过context去进行commit相关的操作, 也可以获取context.state等。但是注意, 这里它们并不是同一个对象, 为什么呢? 我们后面学习Modules的时候, 再具体说

基本使用

```js app
// 进行异步操作

this.$store.dispatch('aUpdateInfo', '我是payload')

actions: { aUpdateInfo(context, payload) { // context: 上下文 可以可理解为store 可以传递参数 setTimeout(() => { // context.state.info.age = 35 不能这样,因为只能在mutations里修改state context.commit('updateInfo',payload) console.log(payload); }, 1000) } }, ``` 这里打开devtools后,添加信息按钮报错,解决方法: devtools导致报错的,把插件里Plugin settings的legacy action开启就好了

如果app想要知道异步操作是否完成,要怎么做?

一般认为 commit成功了就是异步操作完成

  1. 可以把回调函数放到payload中传递 不够优雅 js // app.js this.$store.dispatch('aUpdateInfo', { messege : '我是携带的信息', success () { console.log('异步操作成功'); } })

  2. 更加优雅的方式 dispatch执行发送.then执行回调,

在Action中, 我们可以将异步操作放在一个Promise中, 并且在成功或者失败后, 调用对应的resolve或reject.

Promise经过dispatch中转,在app里调用then方法 js // Promise经过dispatch中转,在app里调用then方法 // app组件 this.$store .dispatch('aUpdateInfo2', 'payload携带的信息') .then( res => { console.log(res); console.log('异步操作成功'); }) // index.js aUpdateInfo2(context, payload) { // 2. actions返回Promise,经过dispatch,在组件中使用then方法 return new Promise((resolve, reject) => { setTimeout(() => { context.commit('updateInfo') console.log(payload); resolve('返回Promise方法') }, 1000) }) }

Module 模块 (套娃)

概念

为什么在Vuex中我们要使用模块呢? Vue使用单一状态树,那么也意味着很多状态都会交给Vuex来管理. 当应用变得非常复杂时,store对象就有可能变得相当臃肿. 为了解决这个问题, Vuex允许我们将store分割成模块(Module), 而每个模块拥有自己的state、mutations、actions、getters等

我们按照什么样的方式来组织模块呢?

代码:

```js // 组件

{ { this.$store.state.a.messege }}

// modules里的a会被放入到state里,所以使用时:this.$store.a.messege updateMessege(){ this.$store.commit('updateMessege', '书籍是人类进步的阶梯') // 一般模块里的mutations方法的名字不要和store里重复 直接commit,提交统一commit } // index.js const moduleA = { state : { messege : '大大怪将军' }, mutations: { updateMessege(state, payload) { state.messege = payload } }, actions : { aUpdateMessege(context) { // 只commit模块内部的mutations,这里的context相当于自己模块 setTimeout(() => { context.commit('updateMessege', '小心超人') }, 1000) } }, getters : { fullmessege(state){ return state.messege + '1111' }, fullmessege2(state, getters) { return getters.fullmessege + '2222' } // 如果想要获取store的state // 在模块内可以有第三个参数rootState fullmessege3(state, getters, rootState) { return getters.fullmessege2 + ' ' + rootState.counter } } } actions还有另一种写法 因为这里的context多了两个属性:rootState,rootGetters 所以如果actions需要store的数据,可以使用 ES6中有个**对象解构**的知识 js // 在actions中 actions : { isEqual({state, commit, rootState}) { if(state.counter == rootState.counter) commit('equal') } }

// 对象解构 const obj = { name : 'yuli', age : '20', address : '洛杉矶' } const {name, age} = obj ``` 解构赋值 解构对象的时候,名称一定要与对象里面的名称一样 顺序可以替换,也可以少分配 数组就得按顺序了,对象是按key来的

// 完整写法是name:name,左边name是匹配模式,右边是变量名,简写就是直接name,
// 如果想改变量名就name:na,一定记住结构时冒号左边是匹配模式,右边是要赋值的变量,
// 具体可以看阮一峰es6

注意:

  1. modules里的a会被放入到state里,所以组件使用时:this.$store.a.messege
  2. 一般模块里的mutations方法的名字不要和store里重复 直接commit,提交统一commit
  3. 如果模块内想要获取store的state,在模块内getters可以有第三个参数rootState,还有rootGetters
  4. actions的参数context相当于自己模块,只能commit模块内部的mutations
  5. dispatch时,模块的actions名字也不要重复
  6. 使用模块的mutations,actions,getters 和store一样,this.$store.方法名

Guess you like

Origin blog.csdn.net/weixin_50945128/article/details/129377820