基于Proxy的小程序状态管理

摘要: 小程序状态管理。javascript

Fundebug经受权转载,版权归原做者全部。html

微信小程序的市场在进一步的扩大,而背后的技术社区仍在摸索着最好的实践方案。我在帮助Nike,沃尔玛以及一些创业公司开发小程序后,依旧认为使用小程序原生框架是一个更高效,稳定的选择,而使用原生框架惟独缺乏一个好的状态管理库,若是不引入状态管理则会让咱们在模块化,项目结构以及单元测试上都有些捉襟见肘。java

目前相对比较稳健的作法是针对redux或者mobx作一个adaptor应用到小程序中,但这样须要本身想办法打包引入外部库,还要想怎么去写这个adaptor,总显得有些麻烦。因而我迸发出一个想法去写一个专用于小程序的状态管理库,它使用起来足够简单而且能够经过小程序本身的npm机制安装。git

目前我已经用这个开源库开发了两个电商小程序,在提升我开发效率的同时亦保证了程序的性能,因此接下来我想谈谈这背后的理念以启发更多开发者尝试新的解决方案。github

基于Proxy的状态管理实现

Proxy在小程序中已经获得了足够好的支持,目前并无发如今任何iPhone或者Android上不能使用Proxy的状况。而基于Proxy的状态管理其实也就是订阅监听的模式,一方面监听数据的变化,另外一方面将这些变化传达给订阅的小程序页面。npm

举一个比较常见的例子,当一个用户从本身的主页进入用户编辑页面,而后更改了本身的用户名点击保存后,用户主页和用户编辑页上的用户名这时候都应该被更新。这背后的程序逻辑则是:更新这个行为将触发Proxy去通知状态管理库,而后状态管理库负责检查此时还在页面栈中的全部页面,更新订阅了用户名这个数据的页面,以下图:编程

Part1: 监听数据变化

监听数据变化其实就是监听各个Store的属性变化,实现上就是在各个Store前面加了一层Proxy,用更直观的图片来表示就是这样:redux

当一个Store被观察之后,它的属性就都变成了Proxy实例,当这个属性值是Object或者Array的时候,它内部的值也会被包装成Proxy实例,这样不管多深层的数据变更都能被监听到。 而在Proxy的后面,Store的属性实际上是被另外一套数据(紫色部分)所维护,这套数据不负责监听,它就是纯数据,针对属性的任何变更最后都会应用到这套数据上来,它的做用是维护和返回最新的数据。小程序

实现细节: https://github.com/wwayne/min...segmentfault

Part2: 页面数据绑定

由于小程序每一个页面的js都是向Page中传递一个对象,这就让咱们有机会包装这个对象,从而实现:

  1. 进入页面后,将页面保存在页面栈中
  2. 未来自状态管理库的数据映射到这个页面的data上来
  3. 页面退出时,将页面从页面栈中移除

实现细节: https://github.com/wwayne/min...

Part3: 页面订阅更新

当数据被监听到变化后,咱们须要依次作两件事,先是找到全部存储在页面栈里的页面,而后根据各个页面订阅的数据来检查变化,若是有变化就通知这些页面,从而让它们去触发setData更新页面。

实现细节:https://github.com/wwayne/min...

使用状态管理的例子

有了状态管理库,如今咱们就来实现一开始举例的更新用户信息的操做,咱们的文件路径以下:

stores/
  user.js
pages/
  userEdit/
     index.js
     index.wxml

1. 首先咱们建立一个Store保存用户的信息,而且监听它的变化:

// stores/user.js
import { observe } from 'minii'

Class UserStore {
  constructor () {
     this.name = 'bob'
  }

  changeName (name) {
     this.name = name
  }
}

export default observe(new UserStore(), 'user')

2. 接着在咱们的小程序页面订阅Store的信息

// pages/userEdit/index.js
import { mapToData } from 'minii'
import userStore from '../../stores/user'

const connect = mapToData(state => (({
  myName: state.user.name
}))
Page(connect({
  updateNameToJames () {
    userStore. changeName('james')
  }
}))

3. 完成,如今能够在页面中使用和更新数据了

// pages/userEdit/index.wxml
<text>{{ myName }}</text>
<button bindtap="updateNameToJames">update name to James</button>

最后

小程序由于有体积的限制,因此我但愿在代码量上也尽可能作到轻量和便捷,因此目前这个状态管理库并无太多很复杂的功能,在小程序打包后所占用的体积也不到1kb,很有点够用就好的意思。

我也已经用它开发了两款小程序,在经历了一段时间的用户使用后,我也更有信心说这个方案在小程序中是可行的。若是你有任何想法和建议,都欢迎告诉我。

项目Github: https://github.com/wwayne/minii


关于做者

Hi, 我是wwayne,是一名居住在上海的独立软件工程师,我正在开发个人新产品 talk-to-kim, 你能够在Github 或者专栏 一我的写代码找到我

关于Fundebug

Fundebug专一于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java线上应用实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了10亿+错误事件,付费客户有阳光保险、荔枝FM、掌门1对一、核桃编程、微脉、青团社等众多品牌企业。欢迎免费试用!

相关文章
相关标签/搜索