个人笔记-vuex

个人笔记-vuex

最近想要沉淀下自己的知识体系,以前光看不记,当时记得,过段时间记忆就模糊了,好脑子不如烂笔头,古人诚不欺我,所以现在决定给用自己的语言方式来给自己记个笔记。

vuex

vuex 有什么好讲的呢,现在的组件通讯有太多方法了,但这种作为vue全家桶里的一员,使用还是蛮广泛的,关于这方面的资料也很多,但我这个笔记是以自己的理解方式用大白话来讲的,有不对的还讲指正。(文章里的代码摘自vuex的中文官网vuex.vuejs.org/zh/)

为什么要用vuex

我们知道,vue是基于组件化的,各管各的,如果这个时候,兄弟组件之间的需要共用某个数据,该怎么通讯呢,方法有很多,比如父子级别的可以通过props和$emit来解决,爷孙级别的可以通过$attrs和$listeners来解决,如果各自相互独立的组件还可能通过中央总线事件来通讯,基本上这三种算是常见的了,当然,也有人说,可以做个全局的变量,然后大家都去拿,在大型项目开发中,这个变量你存了某个值,然后又被另一个人改了,你根本不知道是找哪个人哪行代码改了,这个时候就需要我们进行一个约定,一个特定的地方,保存我们共同的东西,通过约定的方法去更改,以便我们能定位到是谁改了,传了什么东西进来,又方便我们进行追踪。vuex还有一个好处,他里面存的是当前的状态,这就意味着,这里的发生了变化,能响应到对应的组件调用处。

共同的地方-Store

“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。

Vue.use(Vuex) // 重点
const store = new Vuex.Store({
  state: {
    count: 0
  }
})
复制代码

store实例里一定包含一个state对象,里就会存放所有的共有数据状态。

那么组件里面我要去取到这个状态该怎么做呢,首先要注入

const app = new Vue({
  el: '#app',
  // 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件
  store,
  components: { Counter },
  template: `
    <div class="app">
      <counter></counter>
    </div>
  `
})
复制代码

在根组件里注入,这样所属组件就能通过this.$store.state访问到store实例里的state对象了,其实这种方法在vue里很常见,包括路由啊之类的,都是通过在根组件注入,所属组件调用api的方式来取值的。

Getter

Getter有什么用呢?之前我们不是可以直接通过this.$store.state访问到实例里的state对象了吗,那还要这个有什么用呢,在我看来,Getter有三个作用

  • 可以对this.$store.state里的某个属性做计算,比如排序啊,过滤之类的
  • 可以直接通过方法访问,对state里的数据进行筛选,比如store.getters.fun(id)
  • 进行映射,这就要用到mapGetters这个辅助函数:

mapGetters

import { mapGetters } from 'vuex'

export default {
  // ...
  computed: {
  // 使用对象展开运算符将 getter 混入 computed 对象中
    ...mapGetters([
      'doneTodosCount',
      'anotherGetter',
      // ...
    ])
  }
}
复制代码

这样写有什么好处呢,这其实是一个映射,可能不同的理解解释的不一样,大家也不用纠结,这样写了之后可以通过this.doneTodosCount直接拿到,相当于把this.$store.state.doneTodosCount映射成了this.doneTodosCount,这样大家就再也不用噼里啪啦写一堆重复的东西了。

Mutation

之前我们提到,我们要约定一个方法去更新state里数据的状态,这个约定的方法就是提交 mutation。

const store = new Vuex.Store({
  ...
  mutations: {
    increment (state) {
      // 变更状态
      state.count++
    }
  }
})
复制代码

每一个mutation都类似一个事件,increment就是这个事件的type,你不能直接调用这个事件的回调,需要以相应的 type 调用 store.commit 方法:store.commit('increment')

有时候我们要需要对传入的数据进加以第三方数据进行运算,文档里叫提交载荷

// ...
mutations: {
  increment (state, n) {
    state.count += n
  }
}
复制代码

调用store.commit('increment', 10)

文档里说载荷应该是一个对象,在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读,这块表示也蒙。。。

// ...
mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}
复制代码

还有一种对象提交模式,我觉得没啥用,跳过。

mapMutations

同mapGetter,也是映射成this.的写法

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')`
    })
  }
}
复制代码

使用常量替代 Mutation 事件类型

这个看项目吧,大型项目可能需要,各种规范。

敲个黑板: mutation 都是同步事务,什么是同步事务呢,简单的来说就是状态变更都应该在此刻完成,不能有异步的操作,需要加入异步的操作见后面的Action知识点。

Action

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

const store = new Vuex.Store({
  ...
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    /* es6解构写法
    increment ({ commit }) {
        commit('increment')
    }*/
    increment (context) {
      context.commit('increment')
    }
  }
})
复制代码

这个context是个什么东西呢,文档上面是这么说的:与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。

Action 通过 store.dispatch 方法触发:store.dispatch('increment'),同时Action里支持异步操作,举个简单的例子

actions: {
  incrementAsync ({ commit }) {
    setTimeout(() => {
      commit('increment')
    }, 1000)
  }
}
复制代码

action里的写法基本上和mutationu差不多

// 以载荷形式分发
store.dispatch('incrementAsync', {
  amount: 10
})

// 以对象形式分发
store.dispatch({
  type: 'incrementAsync',
  amount: 10
})
复制代码

mapActions

功能同之前的类似

组合 Action

组合Action,我个人用的不多,但原理要了解一下,Action支持异步,所以在Action里可以写异步的commit,包括Promise,包括多个commit依赖性的先后触发。

Module

大型项目多人会用到的东西,各自管各自的模块。每个模块都有自己对应的一套完整的store,然后再通过modules组合到顶层的store里去。

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 的状态
复制代码
对于module,我觉得只需关注几个点就可了:

模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态对象,而不是顶层的了。

const moduleA = {
  state: { count: 0 },
  mutations: {
    increment (state) {
      // 这里的 `state` 对象是模块的局部状态
      state.count++
    }
  },
  actions: {
    incrementIfOddOnRootSum ({ state, commit, rootState }) {
      if ((state.count + rootState.count) % 2 === 1) {
        commit('increment')
      }
    }
  },
  getters: {
    sumWithRootCount (state, getters, rootState) {
      return state.count + rootState.count
    }
  }
}
复制代码

关于这块,我觉得只需关注几个点就Ok了。

现在的state都指局部的状态对象了,顶级的状态为rootState

const moduleA = {
  // ...
  getters: {
    sumWithRootCount (state, getters, rootState) {
      return state.count + rootState.count
    }
  },
  actions: {
    incrementIfOddOnRootSum ({ state, commit, rootState }) {
      if ((state.count + rootState.count) % 2 === 1) {
        commit('increment')
      }
    }
  }
}
复制代码

参数和非module一样,只不过多了第三个参数,这个参数指向顶级状态对象。

命名空间

默认情况下,模块内部的action ,mutation,getter是注册在全局命名空间的–这样使得多个模块能够对同一mutation或者action做出响应;如果希望你的模块更加自包含或者提高可重用性,你可以通过添加namespaced:true 的方式使其成为命名空间模块,当模块被注册后,他的所有getter,action,mutation都会自动根据模块注册的路径调整命名;x

转载于:https://juejin.im/post/5c85cff4f265da2dde0723f2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值