Skip to content

huguobo/miniprogram-observer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

小程序原生简单实现状态管理

背景

小程序本身没提供状态管理功能,可能因为初衷是实现简单的功能,引入类似vuex或者redux等完备状态管理可能会增加包体积。

解决的问题

解决是简单的状态管理需求,比如跨页面状态共享,通信等,处于包体积的原因又不想引入额外的状态管理包。

解决方式

简单参考 vue 响应式的实现,使用 Object.defineProperty 或者 Proxy 对 globalData 实现 get 和 set 的劫持,通过页面 load 时创建对相应属性的 Watcher 来触发回调(在小程序里一般是 setData)来实现状态和UI的绑定。

一些实现

Observer

// 在 app.js 的 onload 方法中调用,使得 globalData 变为响应式
  Observe(data) {
    let _this = this
    for (let key in data) {
      let val = data[key]
      this.observe(data[key])
      let dep = new Dep()
      Object.defineProperty(data, key, {
        configurable: true,
        enumerable: true,
        get() {
          Dep.target && dep.addSubs(Dep.target);
          return val;
        },
        set(newValue) {
          if (val === newValue) {
            return;
          }
          console.log('newValue', newValue);
          val = newValue;
          _this.observe(newValue);
          dep.notify();
        }
      })
    }
  },

Watcher

class Watcher {
  constructor(key, source, cb ){
    this.key = key;
    this.source = source;
    this.cb = cb;
    let arr = key.split('.');
    let val = this.source;
    Dep.target = this;
    arr.forEach(key => {
      val = val[key];
    });
    Dep.target = undefined;
  }

  update() {
    let arr = this.key.split('.');
    let val = this.source;
    arr.forEach(key => {
      val = val[key]
    })
    this.cb(val)  
  }
}

Dep

class Dep {
  constructor() {
    this.subs = []
  }
  addSubs(watcher) {
    this.subs.push(watcher)
  }
  notify() {
    this.subs.forEach(watcher => {
      watcher.update()
    })
  }
}

在页面中添加对globalData中某个字段的响应式更新

Page({
  data: {
    userInfo: {}
  }
  onLoad() {
    let _this = this;
    // 实例化观察者
    app.addWatcher('userInfo', app.globalData, function(newVal){
      console.log('newVal', newVal);
      _this.setData({
        userInfo: newVal
      });
    })
    // balabala...
  }
});

todo

小程序本身的设计感觉风格还是偏 vue,所以这次参考了 vue 响应式的实现, 其实如果想用 redux 的模式也是可以的,但是需要改造更多小程序的 api,来实现 immutable, 如果用 taro 等跨平台框架使用 react 风格编写,可以写个简单的小程序版本的 redux

About

observe the global data using VUE like functional

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published