原生小程序 - 状态管理

732 阅读4分钟

本文正在参加「金石计划 . 瓜分6万现金大奖」

全局数据共享 又被叫做 状态管理 目的是为了解决 层级较远的组件之间进行数据共享的问题

常见的全局数据共享方案有vuex,pinia,redux,mobx等

image.png

在小程序中 可以使用mobx-miniprogrammobx-miniprogram-bindings来实现全局数据共享

  • mobx-miniprogram 用于创建 store实例对象
  • mobx-miniprogram-bingings 用于 把store中共享的数据和方法 绑定到对应的组件和页面中

mobx-miniprogram并不要求在整个小程序中有且只有一个根,可以存在多个对应的store

npm add mobx-miniprogram
npm add mobx-miniprogram-bindings

基本使用

store的定义

store/index.js

import { observable, action } from 'mobx-miniprogram'

export default observable({
  // 被共享的数据
  name: 'Klaus',
  age: 23,

  // 计算属性 
  // 一般情况下 计算属性不需要被设置
  // 只需要根据对应的依赖项进行计算即可
  // 所以在mobx-miniprogram中使用getter定义计算属性
  get doubleAge() {
    return this.age * 2
  },

  // 定义action方法 来修改共享的数据
  // 在mobx-miniprogram中修改共享状态的唯一方法只有通过action方法
  // 直接修改共享状态 会 静默失效
  
  // 为了避免和组件或页面中的方法命名冲突
  // 对应的action方法一般使用Action作为后缀名结尾
  
  // action中传入的方法 必须使用普通函数形式进行定义
  // 不可以使用箭头函数形式进行定义
  // 当使用普通函数形式定义的时候,aciton的回调函数再被调用的时候,会将当前store实例作为this值传入
  // 而使用箭头函数的时候,因为箭头函数内部不绑定this值,所以对应的回调函数中的this值将是undefined
  updateNameAction: action(function(name) {
    this.name = name
  }),

  updateAgeAction: action(function(age) {
    this.age = age
  })
})

在页面中使用

<view>
  <view>{{ name }} - {{ age }} - {{ doubleAge }}</view>
  <button size="mini" type="primary" bindtap="updateName" data-name="Alex">updateName</button>
  <button size="mini" type="primary" bindtap="updateAge" data-age="{{ 32 }}">updateAge</button>
</view>
// 在页面和组件中 引入模块的时候 可以引入第三方模块 也可以引入自定义模块
// 但是在引入自定义模块饿时候,需要注意以下亮点:
// 1. 只能使用相对路径, 不可以使用绝对路径
// 2. 只能省略后缀名, 不能省略文件名,也就是说小程序并不会自动去查找对应的index文件并导入
import { createStoreBindings } from 'mobx-miniprogram-bindings'
import store from '../../store/index'

Page({
  data: {
    // 虽然storeBindings并不需要在页面中使用
    // 所以不设置初始值,也是可以的,但是推荐设置上对应的初始值
    storeBindings: null
  },

  // 在onLoad生命周期中进行数据的绑定
  onLoad() {
    // 使用createStoreBindings方法将数据和方法绑定到第一个参数对象上
    
    // 所以一般第一个参数传入的值就是this
    // 即意味着将对应的数据绑定到当前页面或当前组件上
    
    // createStoreBindings方法会返回一个对象
    //通过该对象可以在组件或页面被移除的时候执行对应的清理工作
    this.storeBindings = createStoreBindings(this, {
      store, // 参数一 --- 数据源
      // 参数二 --- 那些状态需要绑定到当前组件或页面上
      // 绑定后就可以通过 this.xxxx 去进行使用
      fields: ['name', 'age', 'doubleAge'], 
      // 参数三 --- 那些操作需要被绑定到当前组件或页面上
      // 绑定后就可以通过this.xxxx() 去进行调用
      actions: ['updateNameAction', 'updateAgeAction']
    }) 
  },

  // 在onUnload生命周期中进行数据的清理工作
  onUnload() {
    // 通过调用destoryStoreBindings在组件或页面被销毁的时候,清除绑定的共享状态和action函数
    this.storeBindings.destoryStoreBindings()
  },

  updateName(e) {
    // 在组件或页面内不能主动修改store中的数据,只能通过actions来进行修改
    this.updateNameAction(e.currentTarget.dataset.name)
  },

  updateAge(e) {
    this.updateAgeAction(e.currentTarget.dataset.age)
  }
})

在组件中使用

<view>
  <view>{{ name }} - {{ age }} - {{ doubleAge }}</view>
  <button size="mini" type="primary" bindtap="updateName" data-name="Alex">updateName</button>
  <button size="mini" type="primary" bindtap="updateAge" data-age="{{ 32 }}">updateAge</button>
</view>
import { storeBindingsBehavior } from 'mobx-miniprogram-bindings'
import store from '../../../../store/index'

Component({
  // 在组件中使用 store的方式是通过behaviors进行混入操作
  behaviors: [storeBindingsBehavior],

  // 将要使用的数据和方法进行绑定
  storeBindings: {
    store, // 数据源
    // 需要映射的字段
    fields: {
      // key --- 在组件中需要使用到的状态名
      // value --- 有三种使用方式
      // 1. 直接是一个字符串,对应的值是在store中对应的状态名
      name: 'name',
      // 2. 一个函数 --- 参数是store对象,可以通过该对象拿取对应的共享状态
      age: store => store.age,
      // 3. 一个函数 --- 可以是无参的函数,但是在函数体内部依旧可以通过store对象拿到对应的共享状态
      doubleAge: () => store.doubleAge
    },
    // 需要映射的actions
    actions: {
      // key --- 在组件中需要使用的方法名
      // value --- 在store中对应的action方法名 --- ps: 类型是字符串
      updateNameAction: 'updateNameAction',
      updateAgeAction: 'updateAgeAction'
    }
  },

  methods: {
    updateName(e) {
      this.updateNameAction(e.currentTarget.dataset.name)
    },
  
    updateAge(e) {
      this.updateAgeAction(e.currentTarget.dataset.age)
    }
  }
})

本文正在参加「金石计划 . 瓜分6万现金大奖」