mobx-miniprogram
是针对微信小程序开发的一个简单、高效、轻量级状态管理库,它基于Mobx
状态管理框架实现。- 使用
mobx-miniprogram
定义管理的状态是响应式的,当状态一旦它改变,所有关联组件都会自动更新相对应的数据 - 通过该扩展工具库,开发者可以很方便地在小程序中全局共享的状态,并自动更新视图组件,从而提升小程序的开发效率
- 需要注意:在使用
mobx-miniprogram
需要安装两个包:mobx-miniprogram
和mobx-miniprogram-bindings
mobx-miniprogram
的作用:创建Store
对象,用于存储应用的数据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 中不能使用箭头函数,会找不到 this update: action(function () { this.numA += 1 this.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 配置项注册提取的 categoryBehavior behaviors: [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 来代替 numA a: '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 以及 numB update: action(function () { this.numA += 1 this.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' } }] })