Vue入门(九) Vuex

    每一个 Vuex 应用的核心就是 store(仓库),store包含着应用中大部分的状态 (state)。使用vuex来保存我们需要管理的状态值,值一旦被修改,所有引用该值的地方就会自动更新。

Vuex 和单纯的全局对象有以下两点不同:

①若 store 中的状态发生变化,相应的组件也会更新。

②不能直接改变 store 中的状态,通过mutation来改变,可以跟踪每一个状态的变化。

简单应用结构

// 模块化构建系统中要调用Vue.use(Vuex)
const store = new Vuex.Store({
  state: {
    count: 0 },        //状态数据
  mutations: {         //在mutations中修改状态
    increment (state) {
      state.count++     }  }  })
store.commit('increment')          //通过store.commit变更状态

console.log(store.state.count)     // 通过store.state获取状态对象

一、State

Vue使用单一状态树,每个应用只有一个Store实例。

在根实例中注册 store 选项,该 store 实例会注入到根组件下的所有子组件中,且子组件能通过 this.$store 访问到。

一个组件需要获取多个状态时候,可以使用 mapState 辅助函数帮助生成计算属性

import { mapState } from 'vuex'

export default {
  computed: mapState({
    count: state => state.count,     //第一种写法
    countAlias: 'count',     // 第二种,'count' 等同于 `state => state.count`
    countPlusLocalState (state) {     // 使用 `this` 必须使用常规函数
      return state.count + this.localCount    }  })   }
computed: mapState([ 'count'])   //简写:计算属性的名称与 state 的子节点名称相同时

mapState返回的是一个对象,可以通过...mapState与局部计算属性混合使用

computed: {
  localComputed () { /* ... */ },
  ...mapState({  })}       //对象展开运算符...

二、getter

1、 store 中定义“getter”(可以认为是 store 的计算属性),可以以 store.getters 对象属性的形式访问这些值

2、Getter 接受 state 作为其第一个参数,也可以接受其他 getter 作为第二个参数

getters: {
  doneTodos:(){...},
  doneTodosCount: (state, getters) => {
    return getters.doneTodos.length
  }  }

computed: {  //可以在任何组件中访问他们
  doneTodosCount () {
    return this.$store.getters.doneTodosCount  }}

3、通过方法访问

通过让 getter 返回一个函数,来实现给 getter 传参。 getter 在通过方法访问时,每次都会调用,而不会缓存结果。

getTodoById: (state) => (id) => {
    return state.todos.find(todo => todo.id === id) }

4、mapGetters 辅助函数

mapGetters 辅助函数只是将 store 中的 getter 映射到局部计算属性。对象形式可以给getter命名

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

 三、Mutation

 mutation 类似于事件,都有事件类型 (type) 和一个 回调函数 (handler)

1、在回调函数中进行状态更改,它接受 state 作为第一个参数,通过store.commit('回调函数')来调用

store.commit('increment')

2、提交载荷

向 store.commit 传入第二个参数,即 mutation 的 载荷,大多数情况下,载荷应该是一个对象

mutations: {
  increment (state, payload) {
    state.count += payload.amount } }

有两种提交风格,对象或者额外的参数

store.commit('increment', {amount: 10})      //载荷作为参数
store.commit({  type: 'increment',  amount: 10   })   //用tpye,对象风格

 3、需遵循的响应规则

(1)最好提前在store 中初始化好所有属性。使用 Vue.set(obj, 'newProp', 123)添加新属性, 或者以新对象替换老对象。

state.obj = { ...state.obj, newProp: 123 }   //新对象替换老对象

4、使用常量替代mutation计算类型

export const SOME_MUTATION = 'SOME_MUTATION'

import { SOME_MUTATION } from './mutation-types'

 mutations: {//ES2015使用一个常量作为函数名
    [SOME_MUTATION] (state) {... }

5、mutation必须是同步函数

6、在组件中提交mutation

可以在组件中使用 this.$store.commit('xxx') 提交 mutation,

或者使用 mapMutations 辅助函数将组件中的 methods 映射为 store.commit 调用。

四、Action

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

1、Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象

actions: {
    increment (context) {
    context.commit('increment')
 }  }   //简化为increment ({ commit }) {commit('increment')}

2、分发Action

 通过 store.dispatch() 方法触发。Actions 支持同样的载荷方式和对象方式进行分发。

3、在组件中分发

使用 this.$store.dispatch('xxx') 分发 action,或者使用 mapActions 辅助函数将组件的 methods 映射为 store.dispatch 调用。

4、组合Action

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

五、Module

1、Vuex 允许我们将 store 分割成模块(module),每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块modules:{a: moduleA}

const moduleA = {
  state: { ... },
  mutations: { ... },}

2、模块的局部状态

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

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

(3)对于模块内部的 getter,根节点状态会作为第三个参数暴露出来

getters: {  sumWithRootCount (state, getters, rootState) {

3、命名空间

默认模块内部的 action、mutation 和 getter 是注册在全局命名空间的。

可以通过添加 namespaced: true 使其成为带命名空间的模块,子模块会继承父模块的命名空间。

(1)在带命名空间的模块内访问全局内容

rootState 和 rootGetter 会作为第三和第四参数传入 getter,也会通过 context 对象的属性传入 action。

 若需要在全局命名空间内分发 action 或提交 mutation,将 { root: true } 作为第三参数传给 dispatch 或 commit 即可。

(2)在带命名空间的模块内注册全局Action

若要在带命名空间的模块注册全局 action,可添加 root: true,并将这个 action 的定义放在函数 handler 中。

actions: {
   someAction: {
       root: true,
       handler (namespacedContext, payload) { ... } // -> 'someAction'   } }

(3)带命名空间的绑定函数

可以将模块的空间名称字符串作为第一个参数传递给函数,这样所有绑定都会自动将该模块作为上下文。

...mapState('some/nested/module', {
    a: state => state.a,

可以通过使用 createNamespacedHelpers 创建基于某个命名空间辅助函数。它返回一个对象,对象里有新的绑定在给定命名空间值上的组件绑定辅助函数:

4、模块动态注册

 在 store 创建之后,可以使用 store.registerModule 方法注册模块。

// 注册嵌套模块 `nested/myModule`
store.registerModule(['nested', 'myModule'], {...})

 之后就可以通过 store.state.nested.myModule 访问模块的状态。

可以使用 store.unregisterModule(moduleName) 来动态卸载模块,但不能卸载创建Store声明的模块

可以通过store.registerModule('a', module, { preserveState: true })来保留过去的 state

5、模块重用

多个store共用一个模块或一个store中多次注册同一个模块,若使用一个纯对象来声明模块的状态,可能会模块间数据互相污染(类似data)。可以使用一个函数来声明模块状态

六、其他

1、项目结构

应用层级的状态应该集中到单个 store 对象中。若store 文件太大,只需将 action、mutation 和 getter 分割到单独的文件

2、插件

 

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值