乐趣区

Vuex学习整理

Vuex

为 Vue.js 应用程序开发的状态管理模式

解决的问题

由 多个组件共享状态 引起的

1. 多个视图依赖于统一状态
2.  不同视图的行为需要变更统一状态

Store

每个应用只包含一个 Store 实例

  1. Vuex 的状态存储是响应式的。store 中的 state 状态更新立即触发组件更新
  2. 不能直接修改 state。

    • 两种方式:

      • 可以通过 this.$store.state. 变量 = xxx; 进行修改
      • 显式地提交 (commit) mutation

        • this.$store.dispatch(actionType, payload) => mapActions 使用 action 进行更改,异步
        • this.$store.commit(commitType, payload) => mapMutations 使用 mutation 进行更改,同步
      • 可以通过 this.$store.state. 变量 = xxx; 进行修改
    • strict 模式使用第一种方法 vue 会 throw error : [vuex] Do not mutate vuex store state outside mutation handlers。
    • 异同点

      • 共同点:都能触发视图更新(响应式修改)
      • 不同点:

        • strict 模式下,使用第一种方法 vue 会 throw error : [vuex] Do not mutate vuex store state outside mutation handlers。
    • 使用 commit 的优点:

      • vuex 能够记录每一次 state 的变化记录,保存状态快照,实现时间漫游/回滚之类的操作。

核心概念

State 单一状态树

  • 全局的应用层级状态 — 唯一数据源
  • 通过 this.$store.state 可以访问
  • mapState 辅助函数:帮助在组件中引入 state 相关属性,作为组件的计算属性

Getter state 派生状态

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

getters: {
    // 可以通过第二个参数 getters 来使用其他 getter
    getterA: (state, getters) => {return getters.getterB.length},
    getterB: (state) => {return state.todoList;},
    getterC: (state) => (id) => {return state.todoList[id];
    }
}
  • 通过属性访问:this.$store.getters.getterA

    • getter 作为 Vue 的响应式系统的一部分缓存其中
  • 通过方法访问:this.$store.getters.getterC(1)

    • 每次都会去进行调用,而不会缓存结果
  • mapGetters: 将 getters 数据映射到局部(组件)计算属性

Mutation 类似于事件 同步事务

用来更改 Vuex 的 store 中的状态

每个 mutation 包含

  • 事件类型(type)
  • 回调函数 (handler):进行状态更改的地方,接收 state 作为第一个参数

    • 通过 store.commit 方法 调用 mutation handler
    • (state, payload)=> {}
    • payload: 向 store.commit 传入的额外的参数

需遵守 Vue 的响应规则

  1. store 中初始化所有所需属性
  2. 添加新属性用 Vue.set(obj, ‘newProp’, 123); 或者 state.obj = {…state.obj, newProp: 123}

Mutation 必须是同步函数

devtools 不知道什么时候回调函数实际上被调用:在回调函数中进行的状态的改变都是不可追踪的

Action 异步事务

类似 Mutation,不同在于:

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

Action 函数接收与 store 实例具有相同方法和属性的 context 对象

actions: {
    // 常见用法,用 es6 的参数解构来简化代码
    actionA({state, commit, getters, dispatch}) {}}

// 使用 action
store.dispatch('actionA').then(() => {})

Module 模块

解决的问题:应用复杂时(有很多的状态和逻辑),store 对象会很臃肿

每个模块拥有自己的 state、getter、mutation、action、嵌套子模块 module

命名空间

  • 默认注册在 全局命名空间 ,通过设置namespaced:true 可以使其成为带命名空间的模块( 局部化
  • 带命名空间的模块内访问全局内容:

    • state & getters

      getters: {
          // 局部化后
          getterA: (state, getters, rootState, rootGetters) => {}}
      actions: {actionA: ({dispatch, commit, getters, rootGetters, state, rootState}) => {}}
    • action & mutation: 第三参数设为{root: true}
        action: () => {dispatch('actionA', null, { root:true});
            committ('mutationA', null, { root:true});
        }
  • 在带命名空间的模块内注册全局 action

        actions: {
            actionA: {
                root: true,
                handler(namespacedContext, payload) {...}
            }
        }

模块动态注册:store.registerModule(‘moduleName’, {})

- Vue 插件可以在 store 中附加新模块,从而使用 vuex 来管理状态。例如:vuex-router-sync

模块卸载:store.unregisterModule(moduleName)

保留 state: store.registerModule(‘a’, module, { preserveState: true})

模块重用:

const MyReusableModule = {state () {
    return {foo: 'bar'}
  },
  // mutation, action 和 getter 等等...
}

插件

在插件中不允许直接修改状态——类似于组件,只能通过提交 mutation 来触发变化。

const myPlugin = store => {
 // 当 store 初始化后调用
  store.subscribe((mutation, state) => {
    // 每次 mutation 之后调用
    // mutation 的格式为 {type, payload}
  })
}
const store = new Vuex.Store({
 // ...
  plugins: [myPlugin]
})

严格模式

开启严格模式,仅需在创建 store 的时候传入 strict: true

const store = new Vuex.Store({
  // ...
  strict: true
})

在严格模式下,无论何时发生了状态变更且不是由 mutation 函数引起的,将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到

不要在发布环境下启用严格模式:严格模式会深度监测状态树来检测不合规的状态变更,会有性能损失

表单处理

严格模式下,不要用 v -model 绑定 state 数据
** 这样会不使用 mutation 对 state 数据进行更改

两种方法

  • v-model 绑定 value,监听 value 变化然后在事件回调中使用 mutation 去修改 state 数据
  • 双向绑定的计算属性

    computed: {
      message: {get () {return this.$store.state.obj.message},
        set (value) {this.$store.commit('updateMessage', value)
        }
      }
    }

测试

热重载

退出移动版