资讯专栏INFORMATION COLUMN

vuex使用中需要注意的点

妤锋シ / 1990人阅读

摘要:每一条被记录,都需要捕捉到前一状态和后一状态的快照。在组件中提交你可以在组件中使用提交,或者使用辅助函数将组件中的映射为调用需要在根节点注入。当模块被注册后,它的所有及都会自动根据模块注册的路径调整命名。

vuex中几个核心概念: state, getters, mutations, actions, module getters

可以认为是store的计算属性;与计算属性一样,getter的返回值会根据它的依赖缓存起来,且只有当它的依赖值发生变化才会被重新计算

mapGetters

辅助函数仅仅是将 store 中的 getter 映射到局部计算属性:

import { mapGetters } from "vuex"

export default {
  // ...
  computed: {
  // 使用对象展开运算符将 getter 混入 computed 对象中
    ...mapGetters([
      "doneTodosCount",
      "anotherGetter",
      // ...
    ])
  }
}
mutations 只能是同步操作

更改vuex的store中的状态的唯一方法就是提交 mutations
在 mutation 中混合异步调用会导致你的程序很难调试。例如,当你能调用了两个包含异步回调的 mutation 来改变状态,你怎么知道什么时候回调和哪个先回调呢?

mutation必须是同步函数

mutations: {
  someMutation (state) {
    api.callAsyncMethod(() => {
      state.count++
    })
  }
}

现在想象,我们正在 debug 一个 app 并且观察 devtool 中的 mutation 日志。每一条 mutation 被记录,devtools 都需要捕捉到前一状态和后一状态的快照。然而,在上面的例子中 mutation 中的异步函数中的回调让这不可能完成:因为当 mutation 触发的时候,回调函数还没有被调用,devtools 不知道什么时候回调函数实际上被调用——实质上任何在回调函数中进行的状态的改变都是不可追踪的。

在组件中提交mutations

你可以在组件中使用 this.$store.commit("xxx") 提交 mutation,或者使用 mapMutations 辅助函数将组件中的 methods 映射为 store.commit 调用(需要在根节点注入 store)。

import { mapMutations } from "vuex"

export default {
  // ...
  methods: {
    ...mapMutations([
      "increment", // 将 `this.increment()` 映射为 `this.$store.commit("increment")`

      // `mapMutations` 也支持载荷:
      "incrementBy" // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit("incrementBy", amount)`
    ]),
    ...mapMutations({
      add: "increment" // 将 `this.add()` 映射为 `this.$store.commit("increment")`
    })
  }
}
actions 可以是异步操作

action提交的是mutation,而不是直接更改状态

action 可以包含任何异步操作

分发 action 在组件中分发Action

你在组件中使用 this.$store.dispatch("xxx") 分发 action,或者使用 mapActions 辅助函数将组件的 methods 映射为 store.dispatch 调用(需要先在根节点注入 store):

import { mapActions } from "vuex"

export default {
  // ...
  methods: {
    ...mapActions([
      "increment", // 将 `this.increment()` 映射为 `this.$store.dispatch("increment")`

      // `mapActions` 也支持载荷:
      "incrementBy" // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch("incrementBy", amount)`
    ]),
    ...mapActions({
      add: "increment" // 将 `this.add()` 映射为 `this.$store.dispatch("increment")`
    })
  }
}
组合 Action

Action 通常是异步的,那么如何知道 action 什么时候结束呢?更重要的是,我们如何才能组合多个 action,以处理更加复杂的异步流程?

首先,你需要明白 store.dispatch 可以处理被触发的 action 的处理函数返回的 Promise,并且 store.dispatch 仍旧返回 Promise:

// 假设 getData() 和 getOtherData() 返回的是 Promise

actions: {
  async actionA ({ commit }) {
    commit("gotData", await getData())
  },
  async actionB ({ dispatch, commit }) {
    await dispatch("actionA") // 等待 actionA 完成
    commit("gotOtherData", await getOtherData())
  }
}
module

由于使用单一状态树,应用的所有状态会集中到一个比较大的对象;当应用变得非常复杂时,store 对象就有可能变得相当臃肿。

为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:

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 的状态

如果你希望使用全局 stategetterrootStaterootGetter 会作为第三和第四参数传入 getter,也会通过 context 对象的属性传入 action。

命名空间

默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的——这样使得多个模块能够对同一 mutation 或 action 作出响应。

如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced: true 的方式使其成为命名空间模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。例如:

const store = new Vuex.Store({
  modules: {
    account: {
      namespaced: true,

      // 模块内容(module assets)
      state: { ... }, // 模块内的状态已经是嵌套的了,使用 `namespaced` 属性不会对其产生影响
      getters: {
        isAdmin () { ... } // -> getters["account/isAdmin"]
      },
      actions: {
        login () { ... } // -> dispatch("account/login")
      },
      mutations: {
        login () { ... } // -> commit("account/login")
      },

      // 嵌套模块
      modules: {
        // 继承父模块的命名空间
        myPage: {
          state: { ... },
          getters: {
            profile () { ... } // -> getters["account/profile"]
          }
        },

        // 进一步嵌套命名空间
        posts: {
          namespaced: true,

          state: { ... },
          getters: {
            popular () { ... } // -> getters["account/posts/popular"]
          }
        }
      }
    }
  }
})

如果你希望使用全局 state 和 getter,rootState 和 rootGetter 会作为第三和第四参数传入 getter,也会通过 context 对象的属性传入 action。
若需要在全局命名空间内分发 action 或提交 mutation,将 { root: true } 作为第三参数传给 dispatch 或 commit 即可。

需要注意的点 默认情况下,模块内的getter, mutation,action是注册在全局空间的,state只注册在局部命名空间的;

要想使模块内的getter, mutation,action注册在模块命名空间,必须在模块内加上 namespaced: true



使用命名空间在调用action时必须使用

this.$store.dispatch("hero1/getHeroInfo");

computed: {
      doneTodosCount () {
          return this.$store.getters["hero1/doneTodos"][0].item;
      }
  },

参考链接

页面刷新时,store中的数据会清空

解决方案
https://stackoverflow.com/que...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/95493.html

相关文章

  • 使用 Vuex + Vue.js 构建单页应用【新篇】

    摘要:使用构建单页应用新篇在去年的七月六号的时候,发布了一篇使用构建单页应用的文章,文章主要是介绍的基本使用方法,发现对大部分的入门同学有很大的帮助,时至今日还有很多同学不断的点赞与收藏,浏览量最高达到。 使用 Vuex + Vue.js 构建单页应用【新篇】 在去年的七月六号的时候,发布了一篇 使用 Vuex + Vue.js 构建单页应用 的文章,文章主要是介绍 vuex 的基本使用方法...

    crelaber 评论0 收藏0
  • Vuex源码学习(二)脉络梳理

    摘要:各位看官没看过功能梳理的可以先阅读下源码学习一功能梳理前车之鉴有了源码学习的经验,每次看认真钻研源代码的时候都会抽出一小段时间来大体浏览一遍源代码。大体了解这个源代码的脉络,每个阶段做了什么,文件目录的划分。 各位看官 没看过功能梳理的可以先阅读下Vuex源码学习(一)功能梳理. 前车之鉴 有了vue-router源码学习的经验,每次看认真钻研源代码的时候都会抽出一小段时间来大体浏览一...

    chenjiang3 评论0 收藏0
  • 用Vue搭建一个应用盒子(一):todo-list

    摘要:最近在研究的相关知识,最好的学习方法莫过于自己开发一个,这样带着问题来学习,进步自然飞速。在首页里,我们会用写一个导航,通过的路由导航到不同的应用。我们在文件夹里创建一个新的组件。 最近在研究vue的相关知识,最好的学习方法莫过于自己开发一个SPA,这样带着问题来学习,进步自然飞速。于是边查边写差不多花了2周写完了一个todo-list,功能不够完备,但是麻雀虽小,却也是五脏俱全,基本...

    MAX_zuo 评论0 收藏0
  • vuex状态初始化间件设计

    摘要:在之前使用的过程中,对于状态初始化的设计思路,是将其放到一个全局服务中,这样每次进到不同页面,只需要调用同一个全局的动作,就能完成初始化。同时,具体的初始化状态值,则由每个模块自己控制。的中间件有个特点,首先它提供了与动作的切入口。 总算把最近尝试的东西实现出来了,写点文章沉淀一下。 前言 单页面应用在使用单向数据流的设计方案后,状态树的控制就变得至关重要。这里面对的问题在于一个最基础...

    fireflow 评论0 收藏0

发表评论

0条评论

妤锋シ

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<