小程序多状态管理 - 解决跨页面跨组件间通信,简洁小巧高性能,支持微信、支付宝、钉钉、百度、字节、QQ等小程序
npm install mini-stores- 前言
- 安装
- 使用
- 创建store
- 页面内使用
- 组件内使用
- 视图上使用
- 更新状态
- 监听状态
- 使用建议
- 快捷链接
js
npm i mini-stores --save
`使用
#### 创建store
store继承于mini-stores提供的Store类,其中状态定义在data对象内,并支持函数计算属性(计算属性中的this指向store.data对象)
` js
const create = require('mini-stores')class Store extends create.Store {
data = {
title: '小程序多状态管理',
language: "zh_cn",
userName: '李狗蛋',
deptName: '化肥质检部门',
corpName: '富土康化肥厂',
// 函数属性 - 可直接绑定到视图上
description() {
return
我是${this.userName},我在${this.corpName}工作
},
a: {
b: {
// 深层嵌套也支持函数属性
c() {
return this.language + this.description
}
}
}
} onChangeLang() {
if(this.data.language === 'zh_cn') {
this.data.language = 'en_US'
} else {
this.data.language = 'zh_cn'
}
this.update()
}
}
export default new Store()
` #### 页面内使用
在页面的初始化时(onLoad)绑定store,页面销毁时(onUnload)解除store绑定。
store.bind方法使用:store.bind(this, '$data'), 第一个参数this为当前页面实例,第二参数为该store在视图上使用的key名。注意该key在视图上使用时,并不是对应store,而是store.data值。另外定义key名注意不要和现有的私有变量同名,个人建议可以加个前缀(如$),这样可以一眼区分它来自全局状态。
` js
import globalStore from '/stores/globalStore'
import indexStore from '/stores/indexStore'Page({
data: {
privateData: '私有状态' // 私有状态还是通过原有的setData更新
},
onLoad() {
// 绑定实例到store上,第二参数定义视图上使用的key名,命名随意,但注意不要和页面data内的私有变量同名
indexStore.bind(this, '$index');
globalStore.bind(this, '$data');
},
// 页面销毁时解除绑定
onUnload() {
indexStore.unbind(this)
globalStore.unbind(this)
},
handleChangeTitle() {
globalStore.data.title = '新标题'
globalStore.update()
},
handleChangeName() {
indexStore.changeName()
indexStore.update() // 如果changeName方法内调用了this.update方法,此处可以省去调用indexStore.update()
}
});
`#### 组件内使用
和页面内使用一样,在组件初始化时进行store绑定,在组件销毁时解除绑定。
各平台组件生命周期函数写法可能有所区别,根据对应官方文档来写即可。
` js
import globalStore from '/stores/globalStore'
import indexStore from '/stores/indexStore'Component({
data: {
privateData: '私有状态'
},
// 阿里系小程序
didMount() {
indexStore.bind(this, '$index');
globalStore.bind(this, '$data');
},
didUnmount() {
// 组件销毁时解除绑定
indexStore.unbind(this)
globalStore.unbind(this)
},
// 微信小程序等大部分小程序
lifetimes: {
ready() {
indexStore.bind(this, '$index');
globalStore.bind(this, '$data');
},
detached() {
// 组件销毁时解除绑定
helloStore.unbind(this)
globalStore.unbind(this)
},
},
methods: {
handleChangeTitle() {
globalStore.data.title = '新标题'
globalStore.update()
},
handleChangeName() {
indexStore.changeName()
}
}
});
`#### 视图上使用
简单示例:
` js
{{$index.title}}
{{$data.language}}
{{$data.description}}
{{$index.a.b.c}}
{{privateData}}
`#### 更新状态
直接更改对应store.data内的值,最后调用store.upadte()即可。
注:store对象上不要重新定义update属性,避免覆盖
#### 监听状态
添加监听:store.watch.on('key', fn)
移除监听:store.watch.off('key', fn)
key支持简单的对象点路径写法,从而实现监听深层字段,如:'a.b.c.d'
` js
import globalStore from '/stores/globalStore'Page({
onLoad() {
globalStore.bind(this, '$data');
// 添加监听
globalStore.watch.on('language', this.onWatchLang)
},
onUnload() {
globalStore.unbind(this)
// 移除监听,避免内存泄露
globalStore.watch.off('language', this.onWatchLang)
},
onWatchLang(value, oldValue) {
console.log('language change:', value, oldValue)
},
});
`如果觉得每次写移除监听很繁琐,可以在添加监听时传入组件实例(第三个参数),所有当前实例下的监听事件会在store.unbind时自动移除,参考如下:
` js
import globalStore from '/stores/globalStore'Page({
onLoad() {
// 添加监听,第三个参数传入当前实例
globalStore.watch.on('language', this.onWatchLang, this)
},
onUnload() {
globalStore.unbind(this)
},
onWatchLang(value, oldValue) {
console.log('language change:', value, oldValue)
},
});
``2、使用时,建议将状态和逻辑提取到store上,页面只负责处理用户事件的监听和回调,这样的好处是:
* 保持页面代码简洁,可以快速对页面的用户事件一目了然,更好把控业务。
* 状态逻辑在独立的js上,方便实现逻辑复用,且更易于代码测试,对使用函数式编程非常友好。
使用过程中有什么问题或建议可以在Issues进行反馈