原生小程序redux支持库已经上线啦,欢迎star minapp-redux 🌹🌹🌹
也可以通过npm直接引入npm/minapp-redux
写在前面
小程序通过页面或组件各自的 setData 再加上各种父子、兄弟、祖孙等等组件间的通讯会把程序搞成一团浆糊,如果再加上跨页面之间的组件通讯,会让程序非常难维护和调试。
原生小程序生态中的状态管理方案并不多,并且在使用的便捷性上有待商榷(无模块化、几年未更新、代码侵入较大等问题)。
以前我也写过一个原生小程序生态状态管理的库miniprogram-sync-state,这个库在小型项目中使用是没问题的,但是在大型项目中可能就显得捉襟见肘(无模块化是最主要的问题)。
基于不重复造轮子的原则,所以就自己写了一个redux连接库,在微信小程序中也能happy地使用redux啦!
使用100行代码,你就可以拥有:
-
完整redux支持(模块化、异步数据流流、强大的生态)🔥🔥
-
原生page对象结构的connect,类似react-redux(较低的学习成本、便捷的移植方案)🔥🔥
-
最小的diff更新 🔥🔥
-
理论上可以实现时间旅行,但是微信开发者工具不支持
实现理念
为什么是redux
redux作为flux最好的实现之一,他拥有庞大的社区支持与完善的插件支持。并且相对于vuex的定制化,redux作为一个极简的状态管理系统(通过插件实现定制化),天生有易于移植、适用于任何框架的基因。事实上,本文介绍的minapp-redux
也可以归属于redux的定制化插件之一。
状态如何映射到视图
小程序框架没有类似react的props语法,并且由于桥接语法的存在,使得JS层只有data数据才能map到wxml。所以minapp-redux
的connect语法会将第一参数(stateMapFunction)
返回的对象并入page对象定义的data中,使用是需要注意不能有属性重名,否则会有告警:stateMap数据会覆盖page对象中定义的重名data属性。
运行时
由于小程序规范,data中的数据必须在初始化page对象时存在,minapp-redux
提供的connect语法会在小程序初始化时调用,使用Page(connect(stateMapFun, methodMapFun)(pageObject))
语法,pageObject保持了你原本page对象的完整性,便于项目移植或移除minapp-redux
。在后续redux状态改变的时候,redux api subscribe
监听状态变化,并通过保存store实例使用setData更新到视图。
最小的diff更新
minapp-redux
使用了专属于小程序的diff更新机制,在有属性变化的时候会比较新store返回的stateMap与page对象中当前data的属性,并且抽取出变化属性的集合(丢弃相同值的属性),保证最小粒度的更新。值得注意的一点是,有时候我们会使用特别复杂的store对象作为map属性,而对这些复杂对象的diff对比会带来比较大的开销,所以minapp-redux
使用浅比较,当遇到map数据类型为Object时,会将整个对象直接赋值更新。
完整的Redux支持
前面说过minapp-redux
只是作为一个redux的定制化插件存在,它没有改变任何的redux原有功能,任何你需要用到的无浏览器支持的redux插件你都可以无缝使用到把你的minapp-redux
项目中,例如:redux-logger、redux-thunk等等。你也可以基于自己对redux的理解实现自己的模块化管理redux,例如我github项目中的demo,使用reduxUtils模块化封装redux。
具体实现
使用了较为简单的三个api即可保证项目运行,已经稳定使用在多个线上项目中,具体代码可以查看github项目:
使用
引入
- npm构建
npm install minapp-redux --save
- 直接引入
复制项目src文件夹下index.js到项目中
API
const { use, connect, connectComponent } = require(' minapp-redux')
/**
* use
* @param {Object} Store
*/
/**
* connect
* @param {Function} mapStateToData
* @param {Function} mapMethodToPage
* @return {Function}
*/
/**
* connectComponent
* @param {Function} mapStateToData
* @param {Function} mapMethodToPage
* @return {Function}
*/
use
注入redux
// app.js
import { use } from 'minapp-redux'
// redux Store
import Store from '../../store/index'
//inject Store
use(Store)
App({
onLaunch() {}
})
page连接
// pages/login/index.js
import { connect } from '../../libs/minapp-redux'
import * as Actions from '../../store/userInfo/actions.js'
const stateMap = state => {
const { userInfo } = state
return {
hasLogin: userInfo.hasLogin,
userName: userInfo.userName
}
}
const methodMap = (dispatch, state) => ({
login(userName) {
dispatch(
Actions.login({
hasLogin: true,
userName
})
)
}
})
const page = {
data: {
username: ''
},
bindUserNameChange(e) {
this.setData({
username: e.detail.value
})
},
bindLogin() {
if (!this.data.username) return
this.login(this.data.username)
wx.navigateBack({
delta: 1
})
}
}
Page(
connect(
stateMap,
methodMap
)(page)
)
结束
最后打个广告,深圳前海微众银行招收前端开发工程师。
有兴趣的可以给我留言,或者投递简历到我的邮箱: 271253196@qq.com。
快来加入我们吧!
-- The End