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) 
    
    // 工具函数,它接收代码块并在(异步的)动作中执行。这对于即时创建和执行动作非常有用
  • 相关阅读:
    odoo邮箱系统
    运行odoo13,走的odoo12的数据库
    字段`in_group_69`不存在
    odoo库存
    Codeforces 1430E
    AtCoder "Regular Contest 102" D
    AtCoder "Grand Contest 041" E
    ZJNU 2471
    ZJNU 2455
    Codeforces 1426F
  • 原文地址:https://www.cnblogs.com/avidya/p/11654052.html
Copyright © 2011-2022 走看看