mobx-miniprogram
是针对微信小程序开发的一个简单、高效、轻量级状态管理库,它基于Mobx
状态管理框架实现。- 使用
mobx-miniprogram
定义管理的状态是响应式的,当状态一旦它改变,所有关联组件都会自动更新相对应的数据 - 通过该扩展工具库,开发者可以很方便地在小程序中全局共享的状态,并自动更新视图组件,从而提升小程序的开发效率
- 需要注意:在使用
mobx-miniprogram
需要安装两个包:mobx-miniprogram
和mobx-miniprogram-bindings
mobx-miniprogram
的作用:创建Store
对象,用于存储应用的数据mobx-miniprogram-bindings
的作用:将状态和组件、页面进行绑定关联,从而在组件和页面中操作数据
-
mobx-miniprogram 官方文档
-
mobx-miniprogram-bindings 官方文档
一、创建 Store 对象
- 如果需要创建 Store 对象需要使用
mobx-miniprogram
,因此需要先熟悉mobx-miniprogram
三个核心概念:observable
:用于创建一个被监测的对象,对象的属性就是应用的状态(state),这些状态会被转换成响应式数据。action
:用于修改状态(state)的方法,需要使用 action 函数显式的声明创建。computed
:根据已有状态(state)生成的新值。计算属性是一个方法,在方法前面必须加上get
修饰符
-
在项目的根目录下,使用如下命令,将快速在根目录下初始化生成一个
package.json
文件npm init -y
-
安装所需的依赖
npm install mobx-miniprogram mobx-miniprogram-bindings
-
然后 在
微信开发者工具
的左上角 点击》工具》 构建 npm,构建成功后,将会在项目根目录下生成miniprogram_npm
文件夹,可以在miniprogram_npm
文件夹中看见构建的结果 -
在项目的根目录下创建
stores
文件夹,然后在该文件夹下新建numStore.js
文件 -
在
/stores/numStore.js
导入observable
、action
方法。使用observable
方法需要接受一个store
对象,存储应用的状态import {observable,action } from 'mobx-miniprogram'export const numStore = observable({numA: 1,numB: 2,// 使用 action 更新 numA 以及 numB// action 中不能使用箭头函数,会找不到 thisupdate: action(function () {this.numA += 1this.numB += 1}),// 计算属性,使用 get 修饰符,get sum() {return this.numA + this.numB;} })
二、在组件中使用 store 中的数据和方法
-
如果需要在
Page
(页面) 或者Component
(组件)中对共享的数据进行读取、更新操作,需要使用mobx-miniprogram-bindings
-
mobx-miniprogram-bindings
的作用就是将Store
和 页面或组件进行绑定关联 -
如果需要在组件中使用状态,需要
mobx-miniprogram-bindings
库中导入ComponentWithStore
方法,在使用时:需要将Component
(构建组件时的函数) 方法替换成ComponentWithStore
方法,原本组件配置项也需要写到该方法中。在替换以后,就会新增一个storeBindings
配置项,配置项常用的属性有以下三个:store
: 指定要绑定的Store
对象fields
: 指定需要绑定的data
字段actions
: 指定需要映射的actions
方法
注意事项:
导入的数据会同步到组件的 data 中
导入的方法会同步到组件的 methods 中
-
在项目的根目录下的 components 文件夹中(没有该文件夹的需要自己创建)新建 custom01 文件夹,并在该文件夹中创建 custom01组件(在文件夹上点击鼠标右键,选择
新建 component
) -
找到项目根目录下的
app.json
文件,增加如下代码,将 custom01组件注册为 全局组件{// ...其他配置项"usingComponents": {"custom01": "./components/custom01/custom01"} }
-
在
pages/index.wxml
中使用 custom01 组件<custom01 />
-
修改
components/custom01/custom01.js
文件,Component
方法替换成ComponentWithStore
方法import {ComponentWithStore } from 'mobx-miniprogram-bindings'import {numStore } from '../../stores/numStore'ComponentWithStore({data: {},methods: {},// 用来配置当前组件需要与哪些store 进行关联// fields 将被注入到 组件的 data 属性中// actions 将被注入到 组件的 methods 属性中storeBindings: {store: numStore,// 需要使用 store 中的哪些数据fields: ['numA', 'numB', 'sum'],// 需要使用 store 中的哪些方法actions: ['update']} })
-
修改
components/custom01/custom01.wxml
文件<view>{{numA}} + {{numB}} = {{sum}}</view> <button type="primary" bind:tap="update">更新store 中的数据</button>
三、在页面中使用 store 中的数据和方法
- 如果需要在
Page
(页面) 或者Component
(组件)中对共享的数据进行读取、更新操作,需要使用mobx-miniprogram-bindings
mobx-miniprogram-bindings
的作用就是将Store
和 页面或组件进行绑定关联
(一) 方式一:将页面当成组件
- Component 方法用于创建自定义组件。小程序的页面也可以视为自定义组件,因此页面也可以使用 Component 方法进行构建,从而实现复杂的页面逻辑开发。
- 如果我们使用了 Component 方法来构建页面,那么页面中如果想使用
Store
中的数据,使用方式和组件的使用方式是一样的- 从
mobx-miniprogram-bindings
库中导入ComponentWithStore
方法 - 将
Component
方法替换成ComponentWithStore
方法 - 然后配置
storeBindings
从Store
中映射数据和方法即可
- 从
-
假设有一个页面
pages/cate
,修改pages/cate/cate.js
文件// 将页面当成组件 import {ComponentWithStore } from "mobx-miniprogram-bindings"import {numStore } from '../../stores/numStore'ComponentWithStore({data: {msg: '我是cate 页面'},// 用来配置当前组件需要与哪些store 进行关联// fields 将被注入到 组件的 data 属性中// actions 将被注入到 组件的 methods 属性中storeBindings: {store: numStore,// 需要使用 store 中的哪些数据fields: ['numA', 'numB', 'sum'],// 需要使用 store 中的哪些方法actions: ['update']} })
-
修改
pages/cate/cate.wxml
文件<view>{{numA}} + {{numB}} = {{sum}}</view> <button type="primary" bind:tap="update">更新store 中的数据</button>
(一) 方式二:BehaviorWithStore 方法
- 如果不想使用 Component 方法构建页面。这时候需要使用
mobx-miniprogram-bindings
提供的BehaviorWithStore
方法来和Store
建立关联。 - 小程序的 behavior 方法是一种代码复用的方式,可以将一些通用的逻辑和方法提取出来,然后在多个组件中复用,从而减少代码冗余,提高代码的可维护性。在页面中也可以使用
behaviors
配置项
-
假设有一个页面
pages/category
,在pages/category
中新建behavior.js
文件,从mobx-miniprogram-bindings
库中导入BehaviorWithStore
方法import {BehaviorWithStore } from 'mobx-miniprogram-bindings' import {numStore } from '../../stores/numStore'export const categoryBehavior = BehaviorWithStore({storeBindings: {store: numStore,// 需要使用 store 中的哪些数据fields: ['numA', 'numB', 'sum'],// 需要使用 store 中的哪些方法actions: ['update']} })
-
修改
pages/category/category.js
页面import {categoryBehavior } from './behavior'Page({// 使用 behaviors 配置项注册提取的 categoryBehaviorbehaviors: [categoryBehavior] })
-
修改
pages/category/category.wxml
页面<view>{{numA}} + {{numB}} = {{sum}}</view> <button type="primary" bind:tap="update">更新store 中的数据</button>
四、fields、actions 对象写法
-
storeBindings 中的
fields
、actions
有两种写法:数组 或者 对象。前面使用的都是数组写法 -
如果
fields
写成对象方式,有两种写法:-
映射形式:指定 data 中哪些字段来源于
store
以及它们在store
中对应的名字。- 例如
{ a: 'numA', b: 'numB' }
- 例如
-
函数形式:指定 data 中每个字段的计算方法
- 例如
{ a: () => store.numA, b: () => anotherStore.numB }
- 例如
-
-
如果
actions
写成对象方式,只有一种写法:- 映射形式:指定模板中调用的哪些方法来源于
store
以及它们在store
中对应的名字。- 例如
{ buttonTap: 'update' }
- 例如
- 映射形式:指定模板中调用的哪些方法来源于
-
对前面的
组件中使用store 中的的数据和方法
的用例进行(components/custom01/custom01.js)修改import {ComponentWithStore } from 'mobx-miniprogram-bindings'import {numStore } from '../../stores/numStore'ComponentWithStore({data: {},methods: {},// 用来配置当前组件需要与哪些store 进行关联// fields 将被注入到 组件的 data 属性中// actions 将被注入到 组件的 methods 属性中storeBindings: {store: numStore,// 需要使用 store 中的哪些数据// fields: ['numA', 'numB', 'sum'],// actions: ['update']fields: {// 映射形式:需要指定data 中的哪些字段来源于 store, 以及在 store 中的名字是什么// numA: 'numB',// numB: 'numB',// sum: 'sum'// 函数形式:// key: data 中的哪些字段来源于 store// value: 函数。函数内部需要返回对应 store 数据的值// numA: ()=> numStore.numA,// numB: ()=> numStore.numB,// sum: ()=> numStore.sum// 自定义属性:模板中需要使用自定义后的属性,即 .wxml 页面中要用 a 来代替 numAa: 'numA',b: 'numB',total: 'sum'},actions: {//只有映射形式// update: 'update'// 可以改名updateData: 'update',}} })
五、绑定多个 store 以及命名空间
- 在实际开发中,一个页面或者组件可能会绑定多个
Store
,这时候我们可以将storeBindings
改造成数组。数组每一项就是一个个要绑定的Store
。 - 如果多个
Store
中存在相同的数据,显示会出现异常。还可以通过namespace
属性给当前Store
开启命名空间,在开启命名空间以后,访问数据的时候,需要加上namespace
的名字才可以。
-
因为前面的用例中已经创建了
stores/numStore.js
文件,这里不再重复 -
在
stores
文件夹中创建cloneStore.js
文件import {observable,action } from 'mobx-miniprogram'export const cloneStore= observable({numA: 10,numB: 20,// 使用 action 更新 numA 以及 numBupdate: action(function () {this.numA += 1this.numB += 1}),// 计算属性,使用 get 修饰符,get sum() {return this.numA + this.numB;} })
-
假设
pages/category.js
需要使用两个 store,// 将页面当成组件 import {ComponentWithStore } from "mobx-miniprogram-bindings"import {numStore } from '../../stores/numStore'import {cloneStore } from '../../stores/cloneStore'ComponentWithStore({// 使用多个 store 需要将storeBindings 改为数组// 如果 多个 store 引入时,中存在相同的数据和方法,就会报错// 同名时,解决方案一:fields、actions使用对象方式重命名// storeBindings: [{// store: numStore,// fields: {// a: 'numA',// b: 'numB',// total: 'sum',// },// actions: {// numUpdate: 'update'// }// }, {// store: cloneStore,// fields: ['numA', 'numB', 'sum'],// actions: {// cloneUpdate: 'update'// }// }]// 同名时,解决方案二:添加命名空间// 命名空间 只能解决 fields 存在的冲突,actions冲突无法解决// actions冲突 依然需要对象方法// .wxml 中需要使用 命名空间.numA 来访问数据storeBindings: [{namespace: 'numStore',store: numStore,fields: ['numA', 'numB', 'sum'],actions: ['update']}, {namespace: 'cloneStore',store: cloneStore,fields: ['numA', 'numB', 'sum'],actions: {cloneUpdate: 'update'}}] })