在类中使用
在类中使用 Immer
默认情况下,Immer 并不严格处理 Plain 对象的 non-eumerable 属性,如 getters/setters,这是出于性能的考虑。如果你希望这种行为是严格的,你可以用 useStrictShallowCopy(true)来选择。
普通对象(没有原型的对象)、数组、Map 和 Set 总是由 Immer 起草的。其他所有的对象都必须使用 immerable 符号来标记自己与 Immer 兼容。当这些对象中的一个在生产者中被突变时,它的原型在两次拷贝之间被保留下来。
import { immerable } from "immer";
class Foo {
  [immerable] = true; // Option 1
  constructor() {
    this[immerable] = true; // Option 2
  }
}
Foo[immerable] = true; // Option 3
关于如何起草类的语义如下:
- 一个类的草稿是一个新的对象,但它的原型与原始对象相同。
- 当创建一个草稿时,Immer 将把所有自己的属性从基体复制到草稿中。这包括非可数和符号属性。
- 自己的 getters 将在复制过程中被调用,就像 Object.assign 那样。
- 继承的 getters 和方法将保持原样并被草案继承。
- Immer 不会调用构造函数。
- 最终的实例将以与草稿创建时相同的机制来构造。
- 只有那些同时具有 setter 的 getters 在草案中才是可写的,否则值就不能被复制回来了。
因为 Immer 会将对象自己的 getter 解构为正常的属性,所以可以使用在其字段上使用 getter/setter 陷阱的对象,像 MobX 和 Vue 那样。Immer 不支持外来的/引擎原生的对象,如 DOM 节点或缓冲器,也不支持 Map、Set 或数组的子类化,immerable 符号不能用于它们。
因此,当使用日期对象时,你应该总是创建一个新的日期实例,而不是突变一个现有的日期对象。
import { produce, immerable } from "immer";
class ChildClock {
  [immerable] = true;
  constructor(hour, minute) {
    this.hour = hour;
    this.minute = minute;
  }
  get time() {
    return `${this.hour}:${this.minute}`;
  }
  tick() {
    return produce(this, (draft) => {
      draft.minute++;
    });
  }
}
class Clock {
  [immerable] = true;
  childClock1;
  childClock2;
  constructor(hour, minute) {
    this.hour = hour;
    this.minute = minute;
    this.childClock1 = new ChildClock(hour, minute);
    this.childClock2 = new ChildClock(hour, minute);
  }
  get time() {
    return `${this.hour}:${this.minute}`;
  }
  tick() {
    return produce(this, (draft) => {
      draft.minute++;
      draft.childClock1.minute++;
    });
  }
}
const clock1 = new Clock(12, 10);
const clock2 = clock1.tick();
console.log("clock2 === clock1", clock2 === clock1); // false
console.log(
  "clock2.childClock1 === clock1.childClock1",
  clock2.childClock1 === clock1.childClock1
); // false
console.log(
  "clock2.childClock1 instanceof ChildClock",
  clock2.childClock1 instanceof ChildClock
); // true
console.log(
  "clock2.childClock2 === clock1.childClock2",
  clock2.childClock2 === clock1.childClock2
); // true
