mobx 7.0.1 → 7.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4395,17 +4395,40 @@ class ObservableSet {
4395
4395
  if (isObservableSet(other)) {
4396
4396
  other = new Set(other);
4397
4397
  }
4398
- transaction(() => {
4399
- if (Array.isArray(other)) {
4400
- this.clear();
4401
- other.forEach(value => this.add(value));
4402
- } else if (isES6Set(other)) {
4403
- this.clear();
4404
- other.forEach(value => this.add(value));
4405
- } else if (other !== null && other !== undefined) {
4406
- die(41, other);
4407
- }
4408
- });
4398
+ if (Array.isArray(other) || isES6Set(other)) {
4399
+ // Only emit `delete`/`add` events (and `reportChanged`) for values that
4400
+ // actually change, instead of clearing and re-adding everything. `add` and
4401
+ // `delete` are already no-ops for values that are respectively already
4402
+ // present or already absent, so we just need to avoid deleting values that
4403
+ // are part of the replacement. See #3761.
4404
+ transaction(() => {
4405
+ // Collect the desired values for quick lookup. `other` is already a Set
4406
+ // here when it was passed (or snapshotted from an observable set) as one,
4407
+ // so reuse it rather than allocating another; arrays are wrapped (which
4408
+ // also dedupes them).
4409
+ const replacementValues = isES6Set(other) ? other : new Set(other);
4410
+ // Short-circuit the trivial cases: an empty replacement is just a clear,
4411
+ // and replacing into an empty set only needs the adds.
4412
+ if (replacementValues.size === 0) {
4413
+ this.clear();
4414
+ return;
4415
+ }
4416
+ if (this.data_.size === 0) {
4417
+ replacementValues.forEach(value => this.add(value));
4418
+ return;
4419
+ }
4420
+ // Delete values that are not part of the replacement.
4421
+ for (const value of this.data_.values()) {
4422
+ if (!replacementValues.has(this.dehanceValue_(value))) {
4423
+ this.delete(value);
4424
+ }
4425
+ }
4426
+ // Add new values; values that are already present are a no-op.
4427
+ replacementValues.forEach(value => this.add(value));
4428
+ });
4429
+ } else if (other !== null && other !== undefined) {
4430
+ die(41, other);
4431
+ }
4409
4432
  return this;
4410
4433
  }
4411
4434
  toJSON() {