weex中使用数据流工具Vuex实践

2017/08/25 15:19
阅读数 767

原文地址

 

 

背景

 

weex刚开源不久,作为一名前端,当然是抑制不住自己的好奇心想要尝尝鲜。虽然weex的最大亮点在于对于电商类应用场景能够提供快速动态部署的功能,但是用js就能写跑在native端的页面更加吸引我。于是在空余时间就开始捣腾着weex,想做一个native app看看weex有什么“能耐”。

在开发过程中,在体会到weex周边工具带来的效率提升的同时,也发现了不少问题。除了weex本身刚开源肯定会存在各种问题之外,还有一些开发体验的问题。weex相关的问题都在GitHub上提了issue,而开发体验的问题只能自己来解决了。

本文主要记录的就是在用weex开发app过程中遇到的一个最大的问题——数据流管理问题。当然这个问题从某种程度上来说也是我“自找的”,毕竟现在weex大多数的应用场景(电商活动页面)的复杂度是不会有这个问题的。但是有想法就去试试也未尝不是一件好事,所以,接下来都是围绕着用weex来写单页app的情景来讨论的。

在写app的过程中,一旦复杂度稍微上升一点,管理应用状态就是个非常痛苦的事情。在没有引入数据流工具之前,在weex里只能通过组件间的通信和传props来控制数据的流动,页面和交互少一点还好,一旦应用的状态多起来,散落在各处的应用状态就是一团乱麻。

现在前端比较火的框架都有配套的数据流工具,比如React的redux、vue的vuex、angular的自己……可见,现在开源社区有很多可用的数据流方案。于是我就琢磨着给weex引入一套数据流工具。由于weex和vue的渊源,在工具选型方面也没怎么纠结,就vue的亲儿子vuex吧。

vuex简介

VuexVue的作者尤小右开发的为Vue服务的数据流工具。其大致思想跟Redux相近,但在API调用和数据流动方式方面还是有一点区别。例如,vuex中,想要改变state的值需要调用store.dispatch('some action')来调用action,这个action跟Redux中的action概念差不多,可以进行异步操作,然后在action中来调用store.commit('some mutation')触发mutationmutation跟redux的reducer相似,对state直接进行操作,不能做异步操作。(从vuex-v2.0.0开始vuex外部也能调用store.commit()来调用mutation)。

引入过程

了解weex从*.we文件到native页面的过程

Weex相关文档里已经很清楚的解释了这一过程:

作为(不会native的)前端,我们写的.we文件经过webpackweex-loader编译以后,变成了native上JS Framework能够识别的JS Bundle,然后之后的生成weex instanceVirtual DOM就已经脱离我们的管辖范围了。也就是说,在前端deploy之前能做的就只有搞搞字符串的“把戏”。这一点很重要,在下面分析vuex的时候会说到。

分析主角vuex

记得之前在GitHub上看到vuex的issue里有人问能不能把vuex用在别的框架里,作者的答复是

Vuex is not coupled with what rendering platform you use.

于是我就天真的安装了vuex并且引入到了weex项目中,直到报错信息中提到没有找到Vue实例才把我打回现实。看来是要改源码了。

在vuex源码中,进行了一个初始化Vue实例的操作(说好的不依赖呢):

// ...
function initStoreState (store, state, getters) {
  // bind getters
  store.getters = {}
  const computed = {}
  Object.keys(getters).forEach(key => {
    const fn = getters[key]
    // use computed to leverage its lazy-caching mechanism
    computed[key] = () => fn(store)
    Object.defineProperty(store.getters, key, {
      get: () => store._vm[key]
    })
  })

  // use a Vue instance to store the state tree
  // suppress warnings just in case the user has added
  // some funky global mixins
  const silent = Vue.config.silent
  Vue.config.silent = true
  store._vm = new Vue({
    data: { state },
    computed
  })
  Vue.config.silent = silent
}
// ...

报错的来源就是这里,从注释得知,作者用了个Vue实例来存储vuex的state tree,当用户直接访问store.state.someState的时候返回这个Vue实例中保存在data属性里的state,当用户直接访问store.getters.someGetter的时候返回这个Vue实例中保存在computed属性里的getter,仅此而已。吗?

其实作者在这里用到Vue实例是“别有居心”的,因为这样就能复用Vue中的watch机制,当data改变,依赖该data的computed函数就会自动重新计算,因此,在store中的state改变之后,getters就会自动被计算了。

既然说要和Vue解耦,那这个watch机制咋办?好在weex也在组件内部复用了Vue的那套watch,所以理论上这个问题是可以解决的。但是正如之前提到的,weex的实例是在native端的JS Framework生成的,我们在前端是访问不到的。但访问不到weex实例不代表我们不能把state和getters引入到weex实例中,因为实例是会根据我们写的.we文件来生成的,所以思路很清晰,我们在.we文件里引入store不就能在组件内访问state和getters了。(vuex源码的改动不仅限于替换Vue实例为普通对象)

原文地址

展开阅读全文
打赏
0
1 收藏
分享
加载中
更多评论
打赏
0 评论
1 收藏
0
分享
返回顶部
顶部