mobx 7.0.3 → 7.0.5

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # mobx
2
2
 
3
+ ## 7.0.5
4
+
5
+ ### Patch Changes
6
+
7
+ - [`105d66d73529812a8eddc0847891e7f0c574e129`](https://github.com/mobxjs/mobx/commit/105d66d73529812a8eddc0847891e7f0c574e129) [#4713](https://github.com/mobxjs/mobx/pull/4713) Thanks [@xaviergonz](https://github.com/xaviergonz)! - perf: reduce memory used by large, mostly unobserved state. `intercept` / `observe` handler arrays are allocated at their exact size, an observable's internal observers `Set` is released once its last observer leaves, observable objects created with the same `deep` / `autoBind` options share one default annotation instead of allocating their own, and `endBatch()` skips the unobservation pass when nothing is pending.
8
+
9
+ ## 7.0.4
10
+
11
+ ### Patch Changes
12
+
13
+ - [`7d85a68fb7e449650535aba22e47ce4d21bfbc10`](https://github.com/mobxjs/mobx/commit/7d85a68fb7e449650535aba22e47ce4d21bfbc10) [#4592](https://github.com/mobxjs/mobx/pull/4592) Thanks [@VimHax](https://github.com/VimHax)! - Extend IReactionDisposer with Disposable
14
+
15
+ - [`01211a698b64ea94de8e5f276ff8235fcf8ddf96`](https://github.com/mobxjs/mobx/commit/01211a698b64ea94de8e5f276ff8235fcf8ddf96) [#4700](https://github.com/mobxjs/mobx/pull/4700) Thanks [@kubk](https://github.com/kubk)! - Fix `onBecomeObserved` not firing for dependencies gained when an observed computed is recomputed inside an action.
16
+
17
+ - [`6e0a03ef74750b3040c76d3ecc14c4adf202b95a`](https://github.com/mobxjs/mobx/commit/6e0a03ef74750b3040c76d3ecc14c4adf202b95a) [#4710](https://github.com/mobxjs/mobx/pull/4710) Thanks [@kubk](https://github.com/kubk)! - Use TypeScript's built-in `NoInfer` utility instead of a local compatibility alias.
18
+
3
19
  ## 7.0.3
4
20
 
5
21
  ### Patch Changes
@@ -1,5 +1,3 @@
1
1
  import { AnnotationsMap, CreateObservableOptions } from "../internal";
2
- type NoInfer<T> = [T][T extends any ? 0 : never];
3
2
  export declare function makeObservable<T extends object, AdditionalKeys extends PropertyKey = never>(target: T, annotations: AnnotationsMap<T, NoInfer<AdditionalKeys>>, options?: CreateObservableOptions): T;
4
3
  export declare function makeAutoObservable<T extends object, AdditionalKeys extends PropertyKey = never>(target: T, overrides?: AnnotationsMap<T, NoInfer<AdditionalKeys>>, options?: CreateObservableOptions): T;
5
- export {};
@@ -20,7 +20,7 @@ import { $mobx, IDerivation, IDerivationState_, IObservable, Lambda, GenericAbor
20
20
  export interface IReactionPublic {
21
21
  dispose(): void;
22
22
  }
23
- export interface IReactionDisposer {
23
+ export interface IReactionDisposer extends Disposable {
24
24
  (): void;
25
25
  [$mobx]: Reaction;
26
26
  }
@@ -820,6 +820,19 @@ function createAutoAnnotation(options) {
820
820
  extend_
821
821
  };
822
822
  }
823
+ // The auto annotation only depends on `deep` and `autoBind`, so share one instance per combination
824
+ // instead of allocating one for every object created with options
825
+ const autoAnnotations = [autoAnnotation];
826
+ function getAutoAnnotation(options) {
827
+ var _autoAnnotations$idx;
828
+ const deep = options.deep !== false;
829
+ const autoBind = !!options.autoBind;
830
+ const idx = (deep ? 0 : 1) | (autoBind ? 2 : 0);
831
+ return (_autoAnnotations$idx = autoAnnotations[idx]) != null ? _autoAnnotations$idx : autoAnnotations[idx] = createAutoAnnotation({
832
+ deep,
833
+ autoBind
834
+ });
835
+ }
823
836
  function make_$1(adm, key, descriptor, source) {
824
837
  var _this$options_3, _this$options_4;
825
838
  // getter -> computed
@@ -936,7 +949,7 @@ function getEnhancerFromOptions(options) {
936
949
  }
937
950
  function getAnnotationFromOptions(options) {
938
951
  var _options$defaultDecor;
939
- return options ? (_options$defaultDecor = options.defaultDecorator) != null ? _options$defaultDecor : createAutoAnnotation(options) : undefined;
952
+ return options ? (_options$defaultDecor = options.defaultDecorator) != null ? _options$defaultDecor : getAutoAnnotation(options) : undefined;
940
953
  }
941
954
  function getEnhancerFromAnnotation(annotation) {
942
955
  var _annotation$options_$, _annotation$options_;
@@ -1388,7 +1401,10 @@ class ComputedValue {
1388
1401
  reportObserved(this);
1389
1402
  if (shouldCompute(this)) {
1390
1403
  let prevTrackingContext = globalState.trackingContext;
1391
- if (this.keepAlive_ && !prevTrackingContext) {
1404
+ if (!prevTrackingContext && (this.keepAlive_ || this.isBeingObserved)) {
1405
+ // An observed or keep-alive computed can be recomputed by an untracked
1406
+ // read, for example from inside an action. Its dependencies are still
1407
+ // transitively observed and must fire their lifecycle hooks
1392
1408
  globalState.trackingContext = this;
1393
1409
  }
1394
1410
  if (this.trackAndCompute()) {
@@ -1985,34 +2001,41 @@ function endBatch() {
1985
2001
  // the nested call instead of recursing; the outer loop re-reads list.length on
1986
2002
  // every iteration, so it picks up anything the nested dispose() pushes onto the
1987
2003
  // same pendingUnobservations array.
1988
- if (!globalState.isRunningUnobservations) {
1989
- globalState.isRunningUnobservations = true;
1990
- try {
1991
- const list = globalState.pendingUnobservations;
1992
- for (let i = 0; i < list.length; i++) {
1993
- const observable = list[i];
1994
- observable.isPendingUnobservation = false;
1995
- if (!observable.observers_ || observable.observers_.size === 0) {
1996
- if (observable.isBeingObserved) {
1997
- // if this observable had reactive observers, trigger the hooks
1998
- observable.isBeingObserved = false;
1999
- observable.onBUO();
2000
- }
2001
- if (observable instanceof ComputedValue) {
2002
- // computed values are automatically teared down when the last observer leaves
2003
- // this process happens recursively, this computed might be the last observabe of another, etc..
2004
- observable.suspend_();
2005
- }
2006
- }
2004
+ if (!globalState.isRunningUnobservations && globalState.pendingUnobservations.length > 0) {
2005
+ runPendingUnobservations();
2006
+ }
2007
+ }
2008
+ }
2009
+ // Only called when there is something to unobserve, so the common endBatch() skips the
2010
+ // try/finally and the pendingUnobservations reallocation entirely
2011
+ function runPendingUnobservations() {
2012
+ globalState.isRunningUnobservations = true;
2013
+ try {
2014
+ const list = globalState.pendingUnobservations;
2015
+ for (let i = 0; i < list.length; i++) {
2016
+ const observable = list[i];
2017
+ observable.isPendingUnobservation = false;
2018
+ if (!observable.observers_ || observable.observers_.size === 0) {
2019
+ // release the empty Set so unobserved atoms don't keep paying for it
2020
+ observable.observers_ = null;
2021
+ if (observable.isBeingObserved) {
2022
+ // if this observable had reactive observers, trigger the hooks
2023
+ observable.isBeingObserved = false;
2024
+ observable.onBUO();
2025
+ }
2026
+ if (observable instanceof ComputedValue) {
2027
+ // computed values are automatically teared down when the last observer leaves
2028
+ // this process happens recursively, this computed might be the last observabe of another, etc..
2029
+ observable.suspend_();
2007
2030
  }
2008
- globalState.pendingUnobservations = [];
2009
- } finally {
2010
- // Always release the guard, even if an onBUO handler (user code) threw,
2011
- // otherwise every future endBatch() would see isRunningUnobservations
2012
- // stuck true and silently stop draining pendingUnobservations forever.
2013
- globalState.isRunningUnobservations = false;
2014
2031
  }
2015
2032
  }
2033
+ globalState.pendingUnobservations = [];
2034
+ } finally {
2035
+ // Always release the guard, even if an onBUO handler (user code) threw,
2036
+ // otherwise every future endBatch() would see isRunningUnobservations
2037
+ // stuck true and silently stop draining pendingUnobservations forever.
2038
+ globalState.isRunningUnobservations = false;
2016
2039
  }
2017
2040
  }
2018
2041
  /**
@@ -3291,8 +3314,13 @@ function hasInterceptors(interceptable) {
3291
3314
  return interceptable.interceptors_ !== undefined && interceptable.interceptors_.length > 0;
3292
3315
  }
3293
3316
  function registerInterceptor(interceptable, handler) {
3294
- const interceptors = interceptable.interceptors_ || (interceptable.interceptors_ = []);
3295
- interceptors.push(handler);
3317
+ let interceptors = interceptable.interceptors_;
3318
+ if (interceptors) {
3319
+ interceptors.push(handler);
3320
+ } else {
3321
+ // Allocate at the exact size: pushing onto an empty array over-allocates its backing store
3322
+ interceptors = interceptable.interceptors_ = [handler];
3323
+ }
3296
3324
  return once(() => {
3297
3325
  const idx = interceptors.indexOf(handler);
3298
3326
  if (idx !== -1) {
@@ -3324,8 +3352,13 @@ function hasListeners(listenable) {
3324
3352
  return listenable.changeListeners_ !== undefined && listenable.changeListeners_.length > 0;
3325
3353
  }
3326
3354
  function registerListener(listenable, handler) {
3327
- const listeners = listenable.changeListeners_ || (listenable.changeListeners_ = []);
3328
- listeners.push(handler);
3355
+ let listeners = listenable.changeListeners_;
3356
+ if (listeners) {
3357
+ listeners.push(handler);
3358
+ } else {
3359
+ // Allocate at the exact size: pushing onto an empty array over-allocates its backing store
3360
+ listeners = listenable.changeListeners_ = [handler];
3361
+ }
3329
3362
  return once(() => {
3330
3363
  const idx = listeners.indexOf(handler);
3331
3364
  if (idx !== -1) {