zoukankan      html  css  js  c++  java
  • react-mobx-2


    observable

    observable(value)
    @observable classProperty = value

    // 如果 value 是ES6 Map的实例: 会返回一个新的 Observable Map。不只关注某个特定entry的更改,而且对更改添加或删除其他entry时也做出反应。
    
    // 如果 value 是数组,会返回一个 Observable Array。
    
    // 如果 value 是没有原型的对象或它的原型是 Object.prototype,那么对象会被克隆并且所有的属性都会被转换成可观察的。
    
    // 如果 value 是有原型的对象,JavaSript 原始数据类型或者函数,值不会发生变化。如果你需要 Boxed Observable:
    
    1, 显式地调用 observable.box(value) 
    // observable.box(value, options?),
    // 使用 get() 方法可以得到盒子中的当前value,而使用 set() 方法可以更新value
    // 使用 {deep: false} 选项会禁用新值被observable。
    
    
    2, 在类定义时使用 @observable , // 是extendObservable(this, { property: value }) 的语法糖
    3, 调用 decorate()
    4, 在类中使用 extendObservable() 来引入属性
    // 要想使用 @observable 装饰器,首先要确保编译器(babel 或者 typescript)中 装饰器是启用的。
    
    // 默认情况下将一个数据结构转换成可观察的是有感染性的,这意味着 observable 被自动应用于数据结构包含的任何值,或者将来会被该数据结构包含的值。这个行为可以通过使用 装饰器 来更改
    // 为提供的对象创建一个克隆并将其所有的属性转换成 observable
    // 使用 {deep: false} 选项时只有属性会转换成 observable 引用,而值不会改变(这也适用于将来分配的任何值)。
    observable.object(value, decorators?, options?)
    
    observable.array(value, options?)
    // 基于提供的值来创建一个新的 observable 数组。
    
    observable.map(value, options?)
    // 基于提供的值来创建一个新的 observable 映射 创建动态的键集合并且需要能观察到键的添加和移除,可以自由使用任何键而无需局限于字符串。
    extendObservable(target, properties, decorators?, options?)
    // extendObservable 增强了现有的对象,不像 observable.object 是创建一个新对象
    
    // 如果新的属性不应该具备感染性,extendObservable(target, props, decorators?, {deep: false})


    装饰器(Decorators)

    // 如果没有传入装饰器,默认为对任意键值对使用 observable.deep,对 getters 使用 computed 。

    observable.deep: 
    // 所有 observable 都使用的默认的装饰器。它可以把任何指定的、非原始数据类型的、非 observable 的值转换成 observable。
    
    observable.ref: 
    // 禁用自动的 observable 转换,只是创建一个 observable 引用。
    
    observable.shallow: 
    // 只能与集合组合使用。 将任何分配的集合转换为浅 observable (而不是深 observable)的集合。 换句话说, 集合中的值将不会自动变为 observable。
    
    computed: 
    // 创建一个衍生属性

    computed.struct:
    // 与 computed 相同,但是只有当视图产生的值与之前的值结构上有不同时,才通知它的观察者
    action: // 创建一个动作

    action.bound:
    // 创建一个动作, 并将 this 绑定到了实例

    observable.struct:
    // 就像 ref, 但会忽略结构上等于当前值的新值

    // @decorator 语法应用装饰器
    
    import {observable, action} from 'mobx';
    
    class TaskStore {
        @observable.shallow tasks = []
        @action addTask(task) { /* ... */ }
    }
    // decorate() 传入属性装饰器
    
    import {observable, action} from 'mobx';
    
    const taskStore = observable({
        tasks: [],
        addTask(task) { /* ... */ }
    }, {
        tasks: observable.shallow,
        addTask: action
    })
    // 使用 decorate 时,所有字段都应该指定 (毕竟,类里的非 observable 字段可能会更多)
    
    class Person {
        name = "John"
        age = 42
        showAge = false
    
        get labelText() {
            return this.showAge ? `${this.name} (age: ${this.age})` : this.name;
        }
    
        setAge(age) {
            this.age = age;
        }
    }
    
    decorate(Person, {
        name: observable,
        age: observable,
        showAge: observable,
        labelText: computed,
        setAge: action
    })
    // 想要在单个属性上应用多个装饰器的话,可以传入一个装饰器数组。多个装饰器应用的顺序是从右至左。
    
    import { decorate, observable } from 'mobx'
    import { serializable, primitive } from 'serializr'
    import persist from 'mobx-persist'
    
    class Todo {
        id = Math.random();
        title = '';
        finished = false;
    }
    
    decorate(Todo, {
        title: [serializable(primitive), persist('object'), observable],
        finished: [serializable(primitive), observable]
    })

    Computed values(计算值)

    // @computed
    
    import {observable, computed} from "mobx";
    
    class OrderLine {
        @observable price = 0;
        @observable amount = 1;
    
        constructor(price) {
            this.price = price;
        }
    
        @computed get total() {
            return this.price * this.amount;
        }
    }
    // 使用 decorate 引入
    
    import {decorate, observable, computed} from "mobx";
    
    class OrderLine {
        price = 0;
        amount = 1;
        constructor(price) {
            this.price = price;
        }
    
        get total() {
            return this.price * this.amount;
        }
    }
    decorate(OrderLine, {
        price: observable,
        amount: observable,
        total: computed
    })
    // observable.object 和 extendObservable 都会自动将 getter 属性推导成计算属性
    
    const orderLine = observable.object({
        price: 0,
        amount: 1,
        get total() {
            return this.price * this.amount
        }
    })
    // 计算值的 setter
    // setters 不能用来直接改变计算属性的值,可以用来作“逆向”衍生。
    
    const orderLine = observable.object({
        price: 0,
        amount: 1,
        get total() {
            return this.price * this.amount
        },
        set total(total) {
            // 从 total 中推导出 price
            this.price = total / this.amount 
        }
    })    
    // 注意: 永远在 getter 之后 定义 setter,一些 TypeScript 版本会知道声明了两个具有相同名称的属性
    
    class Foo {
        @observable length = 2;
        @computed get squared() {
            return this.length * this.length;
        }
        set squared(value) { 
            this.length = Math.sqrt(value);
        }
    }
    // computed 还可以直接当做函数来调用, 可用于传递在box中计算值
    
    import {observable, computed} from "mobx";
    var name = observable.box("John");
    
    var upperCaseName = computed(() =>
        name.get().toUpperCase() // 使用 .get() 来获取计算的当前值
    );
    // .observe(callback) 来观察值的改变
    var disposer = upperCaseName.observe(change => console.log(change.newValue)); name.set("Dave"); // 输出: 'DAVE'
    computed 接收的第二个选项参数对象选项
    
    name: 字符串, 在 spy 和 MobX 开发者工具中使用的调试名称
    
    context: 在提供的表达式中使用的 this
    
    set: 要使用的setter函数。 没有 setter 的话无法为计算值分配新值。 如果传递给 computed 的第二个参数是一个函数,那么就把会这个函数作为 setter
    
    equals: 默认值是 comparer.default 。它充当比较前一个值和后一个值的比较函数。
    MobX 提供了三个内置 comparer (比较器) 
    comparer.identity: 使用恒等 (===) 运算符来判定两个值是否相同。
    comparer.default: 等同于 comparer.identity,但还认为 NaN 等于 NaN 
    comparer.structural: 执行深层结构比较以确定两个值是否相同。
    
    requiresReaction: 对于非常关键的计算值,推荐设置成 true 。避免没有跟踪该值导致计算结果丢失。
    
    keepAlive:  有无观察者均保持计算。这很容易导致内存泄漏,因为它会导致此计算值使用的每个 observable ,并将计算值保存在内存中!
    // computed 错误处理
    
    const x = observable.box(3)
    const y = observable.box(1)
    const divided = computed(() => {
        if (y.get() === 0)
            throw new Error("Division by zero")
        return x.get() / y.get()
    })
    
    divided.get() // 返回 3
    
    y.set(0) // OK
    divided.get() // 报错: Division by zero
    divided.get() // 报错: Division by zero
    
    y.set(2)
    divided.get() // 已恢复; 返回 1.5

    Actions(动作)

    // 建议在任何更改 observable 或者有副作用的函数上使用动作
    // 动作还能提供非常有用的调试信息
    
    action(fn)
    action(name, fn)
    @action classMethod() {}
    @action(name) classMethod () {}
    @action boundClassMethod = (args) => { body }
    @action(name) boundClassMethod = (args) => { body }
    @action.bound classMethod() {}
    
    // 它接收一个函数并返回具有同样签名的函数
    // 用 transaction、untracked 和 allowStateChanges 包裹起来
    // 默认是使用transaction, 动作会分批处理变化并只在(最外层的)动作完成后通知计算值和反应
    // @action 装饰器 不支持使用 setters
    //  绑定的动作
    //  action.bound 可以用来自动地将动作绑定到目标对象。 
    //  注意,与 action 不同的是,(@)action.bound 不需要一个name参数,名称将始终基于动作绑定的属性。
    
    class Ticker {
        @observable tick = 0
    
        @action.bound
        increment() {
            this.tick++ // 'this' 永远都是正确的
        }
    }
    
    const ticker = new Ticker()
    setInterval(ticker.increment, 1000)
    runInAction(name?, thunk) 
    
    // 工具函数,它接收代码块并在(异步的)动作中执行。这对于即时创建和执行动作非常有用
  • 相关阅读:
    微软外服 AlI In One
    js 循环多次和循环一次的时间的性能对比 All In One
    vue inject All In One
    Excel 表格数据倒置 All In One
    SVG tickets All In One
    OH MY ZSH All In One
    js array for loop performance compare All In One
    mac terminal show You have new mail All In one
    新闻视频 26 制作母版页
    转自牛腩 母版页和相对路径
  • 原文地址:https://www.cnblogs.com/avidya/p/11654052.html
Copyright © 2011-2022 走看看