详解vue.js组件化开发实践(7)

通过在根实例中注册 store 选项,该 store 实例会注入到根组件下的所有子组件中,且子组件能通过  this.$store  访问到。不过事实上,我们几乎不会需要直接引用它。

2.在子组件中,通过在  vuex.getters  选项里定义的 getter 方法来读取状态: 

// MyComponent.js export default { template : '...', data (){ ... }, // 此处为我们从 store 实例中取回状态的位置 vuex : { getters : { // 该 getter 函数将会把仓库的 `store.state.count` 绑定为组件的 `this.count` count : (state) => state.count } } }

请留意 vuex 的这个特殊选项(译注:getters 子对象)。它是我们指定当前组件能从 store 里获取哪些状态信息的地方。它的每个属性名将对应一个 getter 函数。该函数仅接收 store 的整个状态树作为其唯一参数,之后既可以返回状态树的一部分,也可以返回从状态树中求取的计算值。而返回结果,则会依据这个 getter 的属性名添加到组件上,用法与组件自身的计算属性一毛一样。

组件不能直接修改store实例的状态:

请始终记得非常重要的这点,就是:组件永远都不应该直接改变 Vuex store 的状态。因为我们想要让状态的每次改变都很明确且可追踪,Vuex 状态的所有改变都必须在 store 的 mutation handler (变更句柄) 中管理。为了强化该规则,在开启(严格模式(Strict Mode))时,若有 store 的状态在 mutation 句柄外被修改,Vuex 就会报错。现在有了这一规则,我们 Vue 组件的职能就少了很多:他们通过只读的 getter 与 Vuex store 的状态相绑定,组件唯一能影响全局状态的方法就是想办法触发 mutations(我们接下来会谈到)。若有必要,组件仍然能够处理和操作本地状态,但是我们不再在单独的组件中放置任何数据请求或全局状态变更的逻辑。这些操作全部都集中于 Vuex 相关的文件中,这样能让大型应用变得更容易理解和维护。

Mutation

Mutations 本质上是一个事件系统:每个 mutation 都有一个 事件名 (name) 和 一个 回调函数 (handler). 任何一个 Mutation handler 的第一个参数永远为所属 store 的整个 state 对象: 

import Vuex from 'vuex' const store = new Vuex.Store({ state : { count : 1 }, mutations : { INCREMENT (state){ // 改变 state state.count ++ } } })

用全部大写命名 mutation 是一个惯例,方便将它和 actions 区分开。

你不能直接调用 mutation handler. 这里传入 Store 构造函数的选项更像是在注册事件回调:当INCREMENT 事件被触发时,调用这个 handler。触发 mutation handler 的方法是 dispatch 一个 mutation 的事件名:

store.dispatch('INCREMENT')

Mutation必须是同步函数:

  因为当 mutation 触发的时候,回掉函数还没有被调用,我们不知道什么时候回调函数实际上被调用。任何在回调函数中进行的的状态的改变都是不可追踪的。

Mutation必须遵守Vue的响应系统规则:

  1.尽可能在创建 store 时就初始化 state 所需要的所有属性。

  2.当添加一个原本不存在的属性时,需要使用  Vue.set(obj, 'newProp', 123)  或者拷贝并替换原本的对象。利用 stage 2 的语言特性 object spread syntax,我们可以使用这样的语法:   state.obj = {...state.obj, newProp : 123}

Actions

Actions 是用于分发 mutations 的函数。按照惯例,Vuex actions 的第一个参数是 store 实例,附加上可选的自定义参数。 

// 最简单的 action function increment (store){ store.dispatch('INCREMENT') } // 带附加参数的 action // 使用 ES2015 参数解构 function incrementBy ({dispatch}, amount){ dispatch('INCREMENT', amount) }

乍一眼看上去感觉多此一举,我们直接分发 mutations 岂不更方便?实际上并非如此,还记得 mutations 必须同步执行这个限制么?Actions 就不受约束!我们可以在 action 内部执行异步操作,比如执行一个ajax请求数据的操作:

function getData ({dispatch}){ ajax ({ url : "...", data : {...}, success : (data) => { dispatch("SET_DATA", data) } }) }

我们可以这样在组件中调用actions:

// 某组件内部 // 导入actions import {incrementBy} from './actions' const vm = new Vue({ vuex : { getters : { ... }, // state getters actions : { incrementBy } } })

上述代码所做的就是把原生的 incrementBy action 绑定到组件的 store 实例中,暴露给组件一个  vm.increamentBy  实例方法。所有传递给  vm.increamentBy 的参数变量都会排列在 store 变量后面然后一起传递给原生的 action 函数,所以调用  vm.incrementBy(1) 等价于  incrementBy(vm.$store, 1) 。虽然多写了一些代码,但是组件的模板中调用 action 更加省力了:

<button v-on:click="incrementBy(1)">increment by one</button>

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wwfgpj.html