Vuex3.x、Vuex4.x状态管理器学习笔记

2023-02-17 14:26:05 浏览数 (1)

Vuex:https://v3.vuex.vuejs.org/zh

什么是状态管理器?方便调试,方便维护数据。https://vuex.vuejs.org/zh/#什么是“状态管理模式”?

Vuex使用记录

1.在Vue2.x中使用

代码语言:javascript复制
import Vuex from 'vuex'  /* 引入Vuex  */

Vue.use(Vuex)  /* 安装插件 */

 /* 实例化Vuex */
const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count  
    }
  }
})

/* 挂载到所有组件 */
new Vue({
  el: '#app',
  store: store,
})

2.在Vue3.x中使用

代码语言:javascript复制
import { createApp } from 'vue'
import { createStore } from 'vuex'

/* 创建一个新的 store 实例 */
const store = createStore({
  state () {
    return {
      count: 0
    }
  },
  mutations: {
    increment (state) {
      state.count  
    }
  }
})

const app = createApp({ /* 根组件 */ })

/* 将 store 实例作为插件安装 */
app.use(store)

3.辅助函数

mapState、mapGetters、mapActions、mapMutations

当映射的计算属性的名称与 state 的子节点名称相同时,我们也可以给 辅助函数 传一个字符串数组。使用不用的名字时传入一个对象

mapMutation 转换为对应的 this.$store.commit("mutations")

mapActions转换为this.$store.dispatch('action')

在setup中通过useStore()获取store对象实例。无法使用辅助函数

当vuex使用了module模块之后,辅助函数的用法将产生改变

代码语言:javascript复制
  ...mapActions([
    'some/nested/module/foo',  /* -> this['some/nested/module/foo']()*/
    'some/nested/module/bar'   /*-> this['some/nested/module/bar']()*/
  ])

/* 可以在第一个参数中传递模块名,简写 */

  ...mapActions('some/nested/module', [
    'foo', /* -> this.foo() */
    'bar' /* -> this.bar()*/
  ])

4.学习

  1. Vuex 使用单一状态树——是的,用一个对象就包含了全部的应用层级状态。至此它便作为一个“唯一数据源 (SSOT)”而存在。
  2. Vuex的对象可以用过use注入vue应用,成为所有组件的store属性。也可以单独引入这个对象,单独使用。
  3. Vuex的所有方法中,this指向Vuex对象。

5.state(状态/数据)

由于 Vuex 的状态存储是响应式的,从 store 实例中读取状态最简单的方法就是在计算属性中返回某个状态,每当 store.state.count 变化的时候, 都会重新求取计算属性,并且触发更新相关联的 DOM。

当一个组件需要获取多个状态的时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 mapState 辅助函数帮助我们生成计算属性,如:

代码语言:javascript复制
computed: mapState([
  /*映射 this.count 为 store.state.count*/
  'count'
])

mapState返回的是一个包含各种计算属性的对象,可以使用...对象展开运算符抽取出来,成为多个单独的计算属性。

6.getter(state的计算属性?)

从 Vue 3.0 开始,getter 的结果不再像计算属性一样会被缓存起来。这是一个已知的问题,将会在 3.2 版本中修复。

代码语言:javascript复制
getters: {
    doneTodos: (state) => {
      return state.todos.filter(todo => todo.done)
    }
  }

Getter 会暴露为 store.getters 对象,你可以以属性的形式访问这些值。Getter 也可以接受其他 getter 作为第二个参数。

同样的mapGetters 辅助函数可以将 store 中的 getter 映射到局部计算属性:

7.mutation(事件,由commit触发)

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type)和一个回调函数 (handler)。

不能直接调用一个 mutation 处理函数,要唤醒一个 mutation 处理函数,你需要以相应的 type 调用 store.commit 方法:

代码语言:javascript复制
store.commit('increment')

载荷(Payload),可以向 store.commit 传入额外的参数,即 mutation 的载荷(payload),载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读。

一条重要的原则就是要记住 mutation 必须是同步函数。为什么:https://vuex.vuejs.org/zh/guide/mutations.html#mutation-必须是同步函数

同样的mapMutations 辅助函数可以将 store 中的 mutations 映射到局部计算属性:

代码语言:javascript复制
...mapMutations({
    add: 'increment' /*将 `this.add()` 映射为 `this.$store.commit('increment')`*/
})

8.action(异步处理状态,由dispatch触发)

Action 提交的是 mutation,而不是直接变更状态。Action 可以包含任意异步操作。

Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。(通过参数解构拉取context对象上需要的方法直接做为参数)

代码语言:javascript复制
actions: {
  increment ({ commit }) {
    commit('increment')
  }
}
代码语言:javascript复制
/* 参数解构 */
actions: {
    checkout ({ commit, state }, products) {
    }
}

Actions 支持同样的载荷方式和对象方式进行分发(dispatch(action,param))。

同样的mapActions 辅助函数可以将 store 中的 action 映射到局部计算属性。

store.dispatch 可以处理被触发的 action 的处理函数返回的 Promise,并且 store.dispatch 仍旧返回 Promise。

组合action:https://vuex.vuejs.org/zh/guide/actions.html#组合-action

9.模块分割 Module

Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:(通过modules属性进行注册)

代码语言:javascript复制
const moduleA = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

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

const store = createStore({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

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

对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态对象

对于模块内部的 action,局部状态通过 context.state 暴露出来,根节点状态则为 context.rootState。

细节总结

  1. 默认情况下,模块内部的 action 和 mutation 仍然是注册在全局命名空间(在Vuex对象上面,而不是模块对象)的——这样使得多个模块能够对同一个 action 或 mutation 作出响应。Getter 同样也默认注册在全局命名空间。
  2. 可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。
  3. 模块的动态注册和卸载:store.registerModule、store.unregisterModule()(无法卸载声明时的模块)
  4. 类似data属性,有时为了模块重用,如果我们使用一个纯对象来声明模块的状态,那么这个状态对象会通过引用被共享,导致状态对象被修改时 store 或模块间数据互相污染的问题

10.项目结构说明

官方文档:https://vuex.vuejs.org/zh/guide/structure.html

11.组合式API使用

  1. 可以通过调用 useStore 函数,来在 setup 钩子函数中访问 store。这与在组件中使用选项式 API 访问this.$store是等效的。
  2. 官方文档:https://vuex.vuejs.org/zh/guide/composition-api.html
  3. 在其他文件中使用状态管理器时,直接引入创建好的store对象即可。

12.订阅

订阅 store 的 mutation。handler 会在每个 mutation 完成后调用,接收 mutation 和经过 mutation 后的状态作为参数

订阅 store 的 action。handler 会在每个 action 分发的时候调用并接收 action 描述和当前的 store 的 state 这两个参数。 subscribe 方法将返回一个 unsubscribe 函数,当不再需要订阅时,应调用该函数。

官方文档:https://vuex.vuejs.org/zh/api/index.html#subscribe

0 人点赞