阅读 236

mobx的observable做了什么

前言

首先简单介绍一下mobx,他和redux类似数据都是单向流动,通过action改变state,促使view更新。主要为了简化组件间数据共享流程&保证唯一数据源。

使用流程

  1. 定义状态使其可观察 observable
`@observable name = 'zoe';`
`@observable age = '27';`
复制代码
  1. 创建action,一些改变状态值的动作
  @action  addAge = () => {
    this.age += 1;
  };
复制代码
  1. 创建视图响应状态变化 @observer
class Store {
 @observable name = 'zoe'
 @observable age = '27';
 
 @action  addAge = () => {
    this.age += 1;
  };
}

@observer
class Counter extends ReactDOM.Component {
 store = new Store();
  render() {
    return (
      <div>
        {this.store.age}
        <button
          onClick={() => {
            this.store.addAge();
          }}
        >
          +
        </button>
      </div>
    );
  }
}
复制代码

observable

  • 查看通过observable 包装的数据 打印结果

ObservableObjectAdministration

let o=observable({name:'name is zoe'})
console.log({o}) // Proxy {Symbol(mobx administration): ObservableObjectAdministration}
o.name='hello zoe'
console.log(o.name)//name is zoe,除了action外均不能对状态进行更改
复制代码

image.png

  • 小结:observable 将我们普通的数据变成可观察的数据,已经不是原来的那个数据类型(例如:从store里取的数组 就需要toJS(someArray)转下,否则不能直接用Array的原型上的方法)

山寨 一个observable

思路

  1. 通过代理Proxy把数据包装成可观察的代理数据
  2. prox 代理包装过程 要考虑的首要问题是 这个深层嵌套的对象 (用递归 deepProxy)

实现

题外话:ES7的装饰器decorator是依赖于Object.defineProperty

  • 装饰器 获取 target数据进行拦截调用包装函数 对其进行数据包装后 返回同名对应的mobx数据
function observable(target, key, descriptor) {
  //通过 descriptor.initializer 拿到我们装饰的对象的值  进行包装
  if (typeof key === "string") {
    let v = descriptor.initializer();
    v = createObservableAnnotation(v);
    return {
      configurable: false,
      enumerable: true,
      get() {
        return v;
      },
      set(value) {
        v = value;
        //set的时候 autorun执行,自动更新组件
      },
    };
  }

  return createObservableAnnotation(target);
}

复制代码
  • createObservableAnnotation
function createObservableAnnotation(val) {
  let handler = () => {
    // 连接autorun 用的 ,此处不做深入展开
  };
  return deepProxy(val, handler);
}
复制代码
  • deepProxy 递归包装深层嵌套的对象
function deepProxy(val,handler) {
  // val是基本数据类型,则直接返回
  if (typeof val !== "object") return val;
  //遍历每一个属性
  for (let key in val) {
    //递归 实现深层对象的代理
    val[key] = deepProxy(val[key], handler);
  }
   //Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义
  return new Proxy(val,handler());
}
复制代码

小结

今日没有小结 ,中秋快乐

文章分类
前端
文章标签