This repository has been archived by the owner on Jun 6, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 141
weex中使用数据流工具Vuex实践 #62
Comments
中英文之间没空格看着真难受 ( ಠ ಠ ) |
其实我在开始用的 |
最好是和vue的语法是一致的,要不然其实这是学2样不同的东西 |
@sunfuze 其实这也是我在写这篇总结之前的疑惑,这个可能要等weex团队的同学来回答你了。。这个笨办法是在不改动JS Framework的情况下使用的 |
@agileago 如果官方把支持vuex的代码集成到了JSFramework中就不用这么费劲了。。这个是目前情况下的一个笨办法 只是想尝尝鲜 |
已经有个样子了,Weex-X 这儿 https://github.com/Jinjiang/weex-x |
@JimLiu OmniGraffle |
@sunfuze 和 vue 相同的语法在这个分支:https://github.com/alibaba/weex/tree/jsfm-feature-vue |
this._store是undefined 项目是在哪里实例化?? 能否写一个demo? |
@Jinjiang 请问现在weex支持vuex、vue-router了不? 现在可不可以实现vue开发项目(Vue + VueRouter + VueX + VueSource)轻松的在native跑? |
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
背景
weex刚开源不久,作为一名前端,当然是抑制不住自己的好奇心想要尝尝鲜。虽然weex的最大亮点在于对于电商类应用场景能够提供快速动态部署的功能,但是用js就能写跑在native端的页面更加吸引我。于是在空余时间就开始捣腾着weex,想做一个native app看看weex有什么“能耐”。
在开发过程中,在体会到weex周边工具带来的效率提升的同时,也发现了不少问题。除了weex本身刚开源肯定会存在各种问题之外,还有一些开发体验的问题。weex相关的问题都在GitHub上提了issue,而开发体验的问题只能自己来解决了。
本文主要记录的就是在用weex开发app过程中遇到的一个最大的问题——数据流管理问题。当然这个问题从某种程度上来说也是我“自找的”,毕竟现在weex大多数的应用场景(电商活动页面)的复杂度是不会有这个问题的。但是有想法就去试试也未尝不是一件好事,所以,接下来都是围绕着用weex来写单页app的情景来讨论的。
在写app的过程中,一旦复杂度稍微上升一点,管理应用状态就是个非常痛苦的事情。在没有引入数据流工具之前,在weex里只能通过组件间的通信和传props来控制数据的流动,页面和交互少一点还好,一旦应用的状态多起来,散落在各处的应用状态就是一团乱麻。
现在前端比较火的框架都有配套的数据流工具,比如redux、react的flux、vue的vuex、angular的自己……可见,现在开源社区有很多可用的数据流方案。于是我就琢磨着给weex引入一套数据流工具。由于weex和vue的渊源,在工具选型方面也没怎么纠结,就vue的亲儿子vuex吧。
vuex简介
Vuex是Vue的作者尤小右开发的为Vue服务的数据流工具。其大致思想跟Redux相近,但在API调用和数据流动方式方面还是有一点区别。例如,vuex中,想要改变state的值需要调用
store.dispatch('some action')
来调用action
,这个action
跟Redux中的action
概念差不多,可以进行异步操作,然后在action
中来调用store.commit('some mutation')
触发mutation
,mutation
跟redux的reducer
相似,对state直接进行操作,不能做异步操作。(从vuex-v2.0.0
开始vuex外部也能调用store.commit()
来调用mutation
)。引入过程
了解weex从*.we文件到native页面的过程
Weex的相关文档里已经很清楚的解释了这一过程:
作为(不会native的)前端,我们写的
.we
文件经过webpack
的weex-loader
编译以后,变成了native上JS Framework能够识别的JS Bundle,然后之后的生成weex instance
和Virtual DOM
就已经脱离我们的管辖范围了。也就是说,在前端deploy
之前能做的就只有搞搞字符串的“把戏”。这一点很重要,在下面分析vuex
的时候会说到。分析主角vuex
记得之前在GitHub上看到
vuex
的issue里有人问能不能把vuex用在别的框架里,作者的答复是于是我就天真的安装了
vuex
并且引入到了weex
项目中,直到报错信息中提到没有找到Vue
实例才把我打回现实。看来是要改源码了。在vuex源码中,进行了一个初始化Vue实例的操作(说好的不依赖呢):
报错的来源就是这里,从注释得知,作者用了个
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实例为普通对象)我们将
store.state
和getter
分别注入到了weex组件的data
和computed
中,这样我们相当于就利用了weex内部的watch机制,跟之前用Vue
实例效果是一样的。虽然能够正常工作,但是我们想要在weex组件中用到vuex的store,那每次我们都需要手动引入store.js
文件来访问store。这样显然是不太优雅的,我们来看看Vue是怎么做的,以下代码来自Vuex官方文档简单一句
Vue.use(Vuex)
然后在根组件内部引入store
属性就能将store引入到vue的子组件里,通过在vue组件内部调用this.$store
就能访问到store,而不是每个子组件引入一次store。但是由于weex没有提供这样的接口,因此又只能自己想办法了。weex transformer分析
在前端,我们编写的是
.we
文件,native的JS Framework拿到的是JS Bundle,那从.we
到JS Bundle的过程中发生了什么?这就要看transformer做了什么事情了。先看看以下.we
文件和它对应的JS Bundle是什么样子的:可以看出,从
.we
文件转换到到JS Bundle的过程中,实际上就是对.we
文件进行了编译,将他转换成JS Framework能够识别的格式。所以可以理解为,JS Bundle就是格式不同的.we
文件,只要.we
文件的格式是符合transformer要求的,那么transformer就可以输出符合JS Framework要求的JS Bundle。所以,只要保证在每次转换前的文件格式符合转换器的要求,我们对转换前的文件做怎样的修改都可以。因此,为了解决需要在每个weex组件内部
require(xxx/store)
的问题,我们可以写一个loader,在transformer之前将require
语句引入到每个.we
文件中,这样就解决了这个问题。另外,要用weex组件的watch机制,就需要在组件的data中引入
store.state
,所以loader也需要做这个事情。weex+vuex使用方法
安装weex-vuex-loader
weex-vuex-loader是上面提到的在weex transformer之前处理
.we
文件的webpack loader。首先在项目下安装weex-vuex-loader:
然后打开
webpack.config.js
,在weex-loader之后添加weex-vuex-loader:后面
?
之后的store
是用户能够自定义的,你可以替换成你想要的变量,这个变量就是在weex组件中通过this
访问到的vuex的store
。例如上面的例子中,?
之后是store
,那么在weex组件中就可以通过this.store
访问vuex的store
。这样做的原因是,本来想像
Vue
一样,通过this.$store
来访问,但是JS Framework的规则不允许weex组件中的data里有$
开头的变量,因为这些变量是事先定义好的weex组件的vm的属性。所以,这里只能将默认的访问方式改为
this._store
,也就是在weex-vuex-loader
后面不指定变量名的默认情况。考虑到不是人人都喜欢这样的访问方式,干脆就改成能够自定义了。安装vuex-weex
vuex-weex是为了让Vuex适配Weex,更改了源码之后的Vuex。然后在项目根目录下
src/vuex/
中添加store.js
文件,写法参考vuex-v2.0.0-rc.1。由于现在weex还不支持ES6语法,因此store.js
中还是用ES5来写吧:需要注意的是,这里getter的第一个参数是
store
,并不是Vuex中原本的state
。编写.we文件
完成了上面两个步骤之后,就能愉快地在.we文件中使用vuex了:
还存在的问题
Vue中的action是支持异步操作的,返回Promise即可,weex也在native端支持了Promise,看起来不应该有什么问题。但是我在使用过程中发现,在action中加入异步操作之后,在
then()
中调用了commit()
来触发某个mutation之后,虽然mutation会执行(例如改变某个state),并且weex组件中调用了依赖这个state的getter的computed函数也会执行,但是视图是不会更新的,除非你再触发一个事件(比如click事件),之后视图才会更新。所以,为了避免这个问题,建议将异步操作放在weex组件内部,官方也提供了streamAPI来支持异步操作。
说到stream模块,在目前的weex-v0.6.1中,在ios端传给回调函数的
response
的类型是string
而不是object
,所以在处理之前需要先JSON.parse(response)
。这个BUG将会在下个版本被修复。这样就能如丝般顺滑地体验weex+vuex了。
The text was updated successfully, but these errors were encountered: