yaofly2012 / note

Personal blog
https://github.com/yaofly2012/note/issues
44 stars 5 forks source link

MobX #62

Open yaofly2012 opened 5 years ago

yaofly2012 commented 5 years ago

Becoming fully reactive: an in-depth explanation of MobX

  1. 是什么? a (simple, scalable)state management solution

  2. 要解决的问题: producing an consistent state and state that is in-sync with local variables that linger around.

  3. How: The strategy to achieve that is simple: Make sure that everything that can be derived from the application state, will be derived. Automatically.

Issues:

  1. 当状态改变时,所有衍生都会进行原子级的自动更新。因此永远不可能观察到中间值

  2. 什么是“原子级的自动更新” ?

  3. 不可能观察到中间值 ?

  4. Make sure that everything that can be derived from the application state, will be derived. Automatically.

  5. 可以直接修改state的值,为啥建议统一使用action修改state? action能带来什么好处

concern:

  1. mobx并不依赖reactjs,它是个单独的库,可以单独使用。

概念

  1. state 表示应用的原始数据模型(就像excel单元格的原始数据)
  2. derivation 依赖state值的数据
  3. computed value 基于原子state产生新的state值(就像excel公式)
  4. reaction(I/O, DOM update, Networking) 特殊的derivation。不会产生新的值,只是基于值的变化产生一些操作。 可以认为reaction就是个回调函数,当依赖的state发生变化时会自动触发该回调函数执行。
  5. dependency tracking
  6. abservable MobX can track all the changes that are being made

怎么算是依赖:

@computed get report() {
        if (this.todos.length === 0)
            return "<none>";
        return `Next todo: "${this.todos[0].task}". ` +
            `Progress: ${this.completedTodosCount}/${this.todos.length}`;
    }

表示计算值report依赖this.todos的第一个元素的task属性和length属性,并不是表示report依赖this.todos

  1. actions 修改state。state依赖树的更新是同步的(这样才能保证数据统一)

原则

当状态改变时,所有衍生都会进行原子级的自动更新。因此永远不可能观察到中间值。 所有衍生默认都是同步更新。这意味着例如动作可以在改变状态之后直接可以安全地检查计算值。 计算值 是延迟更新的。任何不在使用状态的计算值将不会更新,直到需要它进行副作用(I / O)操作时。 如果视图不再使用,那么它会自动被垃圾回收。 所有的计算值都应该是纯净的。它们不应该用来改变状态。

Issues?

  1. 计算值 是延迟更新的。任何不在使用状态的计算值将不会更新,直到需要它进行副作用(I / O)操作时。 如果视图不再使用,那么它会自动被垃圾回收。

autorun函数

  1. 通过autorun函数注册的回调函数会在两种情况下执行:
    • 首次调用autorun函数注册回调函数;
    • 当函数体内涉及的state发生变更时。
  2. autorun如何解析回调函数体内对state的依赖的?

Demoing过程遇到的问题

  1. Support for the experimental syntax 'classProperties' isn't currently enabled
  2. image

  3. {
    "presets": ["next/babel"],
    "plugins": [
        ["@babel/plugin-syntax-decorators", {"legacy": true}]
    ]
    }

    image

yaofly2012 commented 5 years ago

Making React reactive

  1. 原来右setState方法触发的render方法调用,现在通过autorun函数注册的reaction触发。两者有什么异同?
yaofly2012 commented 5 years ago

函数响应式编程(Transparent Functional Reactive Programming)

但是 MobX 把透明的函数响应式编程(Transparent Functional Reactive Programming)提升到了一个更好的水平并且提供了独立的实现。它以一种无障碍、同步、可预见和高效的方式实现了 TFRP。

yaofly2012 commented 5 years ago

observable

observable函数

  1. 在把对象转成observale对象时通过clone的方式,不影响原来的对象。

    var list = [1, 2, 4];
    var list2 = observable(list);

    list2是observable对下,list依旧是原来的数组。

  2. 只能用于普通对象(原型是 Object.prototype或者Null的对下),否则报错:

    mobx.module.js:90 Uncaught Error: [mobx] The provided value could not be converted into an observable. If you want just create an observable reference to the object use 'observable.box(value)'

  3. 如果普通对下的属性是个非普通对象,observable只会把该属性转成observable,不会把非普通对象的属性转成observable。

    var p = {
        name: 'john'
    }
    var c = Object.create(p, {
        age: {
            value: 23,
            writable: true,
            enumerable: true,
            configurable: true
        }
    });
    
    var observableObj = observable({
        name: 'john',
        child: c
    })
    
    autorun(() => {
        console.log(observableObj.child.age)
    })
    
    setInterval(() => {
        observableObj.child.age = Math.random()
    }, 1000)

    上例中name和child属性会转成observable,而child.age属性不会转成observable。

  4. observable对象的属性如果赋值新的对象,则也会递归的遍历新对下转成observable。

    function demo4() {
    var a = observable({name: 'john'});
    a.name = {
        age: 22 // age属性也会被转成observable
    }
    autorun(() => {
        console.log(a.name.age)
    })
    setInterval(() => {
        a.name.age = Math.random();
    }, 1000)
    }
  5. 特殊的name属性,命名observable对象。

    observable.array

  6. 重写array内置的方法

  7. 扩展了array的方法

observable.box

  1. 原理就是把传入的值转成对下的属性。
  2. observable.box(primitiveVal) 会重写返回值的valueOf方法,是的返回值对象的行为尽量跟原始值一样。
    var name = 'john';
    var name2 = observable.box(name);
    console.log(`${name == name2}`); // true
  3. observable.box传入引用类型时也会被封装的。

Issues

  1. observable和observable.object关系?

  2. obsevabe函数可以使用对象,数组,Map了,为啥还单独暴露observable.object/array/map方法?

  3. 两者的区别? 先autorun,再添加元素

    autorun(() => {
        console.log(`${todos[2] ? todos[2].name : 'no ele in index 2'}`)
    })
    todos[2] = { name: 'john', title: 'a person', completed: false };
    setTimeout(() => {
            todos[2].name = 'lulu' // 不会触发回调
        }, 1000)

    先添加元素,后autorun

    todos[2] = { name: 'john', title: 'a person', completed: false };
    autorun(() => {
        console.log(`${todos[2] ? todos[2].name : 'no ele in index 2'}`)
    })
    setTimeout(() => {
            todos[2].name = 'lulu' // 会触发回调
        }, 1000)
  4. mobx.module.js:3247 Uncaught Error: [mobx.array] Index out of bounds, 3 is larger than 2

  5. 为什么这样做?

    observableArray.sort and reverse will not change the array in-place, but only will return a sorted / reversed copy

  6. 因为什么原因导致mobx4及以下版本的obvervable数组是个伪数组?

  7. 为啥没有observable Set ?

  8. 如何给根state对象增加新的abservable属性?

    • 一般对象
    • 类对象
  9. 在data Function里使用数组的map函数,为什么会对length属性进行的tracking ?

yaofly2012 commented 5 years ago

drivation

概念

  1. disposer
  2. 依赖树
  3. 追踪函数(tracking Function) 有些函数即是追踪函数又是受影响函数(computed, autorun的第一个参数)。
  4. 受影响函数(Effort Function)

when

响应式的调用predicate函数,当predicate函数返回的Promise 被resolved或者返回true,触发effort回调函数调用,并自动取消自动运行程序。

注意:

  1. MobX 不会追踪还不存在的索引或者对象属性(当使用 observable 映射(map)时除外)

issues ?

  1. 这通常是当你需要从反应式代码桥接到命令式代码的情况 ?

什么是“反应式”,“命令式”

  1. when有什么应用场景呢?
  2. React组件应用observer时,还能利用setState的批处理优化吗
  3. console.log 是异步 API,它只会稍后对参数进行格式化,因此 autorun 不会追踪 console.log 访问的数据

什么?

yaofly2012 commented 5 years ago

一、action

1.1 transaction

批处理action函数内部对state修改,即:

  1. 当action函数执行完后才通知依赖的derivations(computed,reactions);
  2. 如果action函数里存在其他action函数,则等所有action函数执行完后再通知依赖的derivations(computed,reactions)。

二、方法

runInAction

action(fn)()的语法糖,立即执行fn。

flow函数

  1. 返回Promise;
  2. flow函数遍历生成器函数的返回值各个状态添加了控制,async/await却不能实现更细微的控制?

三、issues:

  1. 使用action带来哪些好处?怎么实现的?
  2. action.bind和箭头函数一起使用?
  3. action装饰器\函数只能处理同步代码
  4. 怎么做到多action函数原子性的?
  5. flow can be used only as function and not as decorator 为什么?

四、is @action really necessary?

yaofly2012 commented 5 years ago

基础

  1. ES6 proxy
  2. 生成器