基于Proxy的小程序状态管理实现


Posted in Javascript onJune 14, 2019

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

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

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

基于Proxy的状态管理实现

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

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

基于Proxy的小程序状态管理实现

Part1: 监听数据变化

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

基于Proxy的小程序状态管理实现

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

实现细节: https://github.com/wwayne/minii/blob/master/src/api/observe.js

Part2: 页面数据绑定

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

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

实现细节: https://github.com/wwayne/minii/blob/master/src/api/mapToData.js

Part3: 页面订阅更新

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

实现细节:https://github.com/wwayne/minii/blob/master/src/core.js

使用状态管理的例子

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

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
js宝典学习笔记(上)
Jan 10 Javascript
JavaScript学习笔记(十)
Jan 17 Javascript
JQquery的一些使用心得分享
Aug 01 Javascript
javaScript让文本框内的最后一个文字的后面获得焦点实现代码
Jan 06 Javascript
JavaScript的模块化:封装(闭包),继承(原型) 介绍
Jul 22 Javascript
JS中检测数据类型的几种方式及优缺点小结
Dec 12 Javascript
Angular中实现树形结构视图实例代码
May 05 Javascript
vue.js移动端app实战1:初始配置详解
Jul 24 Javascript
解决npm安装Electron缓慢网络超时导致失败的问题
Feb 06 Javascript
webpack4的迁移的使用方法
May 25 Javascript
Element图表初始大小及窗口自适应实现
Jul 10 Javascript
vue pages 多入口项目 + chainWebpack 全局引用缩写说明
Sep 21 Javascript
深度了解vue.js中hooks的相关知识
Jun 14 #Javascript
Vue 实现前进刷新后退不刷新的效果
Jun 14 #Javascript
在Vue中使用icon 字体图标的方法
Jun 14 #Javascript
移动端底部导航固定配合vue-router实现组件切换功能
Jun 13 #Javascript
后台使用freeMarker和前端使用vue的方法及遇到的问题
Jun 13 #Javascript
vue路由插件之vue-route
Jun 13 #Javascript
在JavaScript中使用严格模式(Strict Mode)
Jun 13 #Javascript
You might like
php date与gmdate的获取日期的区别
2010/02/08 PHP
PHP中把错误日志保存在系统日志中(Windows系统)
2015/06/23 PHP
功能强大的PHP图片处理类(水印、透明度、旋转)
2015/10/21 PHP
Laravel 5.5基于内置的Auth模块实现前后台登陆详解
2017/12/21 PHP
PHP7 foreach() 函数修改
2021/03/09 PHP
js可突破windows弹退效果代码
2008/08/09 Javascript
跨浏览器开发经验总结(三)   警惕“IE依赖综合症”
2010/05/13 Javascript
javascript实现动态导入js与css等静态资源文件的方法
2015/07/25 Javascript
Angularjs实现多个页面共享数据的方式
2016/03/29 Javascript
JavaScript笔记之数据属性和存储器属性
2016/03/31 Javascript
jQuery  ready方法实现原理详解
2016/10/19 Javascript
微信小程序之仿微信漂流瓶实例
2016/12/09 Javascript
详解使用Vue Router导航钩子与Vuex来实现后退状态保存
2017/09/11 Javascript
JavaScript实现二叉树的先序、中序及后序遍历方法详解
2017/10/26 Javascript
微信小程序开发背景图显示功能
2018/08/08 Javascript
JS封装的模仿qq右下角消息弹窗功能示例
2018/08/22 Javascript
使用JavaScript通过前端发送电子邮件
2020/05/22 Javascript
Python标准库defaultdict模块使用示例
2015/04/28 Python
Unicode和Python的中文处理
2017/03/19 Python
python实现的二叉树定义与遍历算法实例
2017/06/30 Python
Python温度转换实例分析
2018/01/17 Python
Python实现截取PDF文件中的几页代码实例
2019/03/11 Python
tensorflow获取预训练模型某层参数并赋值到当前网络指定层方式
2020/01/24 Python
Python 实现一个简单的web服务器
2021/01/03 Python
让IE6支持css3,让 IE7、IE8 都支持CSS3
2011/10/09 HTML / CSS
微信小程序之html5 canvas绘图并保存到系统相册
2019/06/20 HTML / CSS
MYSQL相比于其他数据库有哪些特点
2013/07/19 面试题
学期研究性学习个人的自我评价
2014/01/09 职场文书
学生手册家长评语
2014/02/10 职场文书
测绘专业大学生职业生涯规划书
2014/02/10 职场文书
计算机相关专业自荐信
2014/07/02 职场文书
学校德育工作总结2015
2015/05/11 职场文书
街道办残联2016年助残日活动总结
2016/04/01 职场文书
用Python提取PDF表格的方法
2021/04/11 Python
python-for x in range的用法(注意要点、细节)
2021/05/10 Python
Java 超详细讲解设计模式之中的抽象工厂模式
2022/03/25 Java/Android