mobx 6.16.1 → 7.0.1
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 +86 -0
- package/README.md +9 -13
- package/dist/api/action.d.ts +6 -4
- package/dist/api/annotation.d.ts +0 -1
- package/dist/api/computed.d.ts +4 -7
- package/dist/api/configure.d.ts +0 -1
- package/dist/api/decoratorannotation.d.ts +3 -0
- package/dist/api/decorators.d.ts +0 -19
- package/dist/api/flow.d.ts +4 -5
- package/dist/api/makeObservable.d.ts +2 -3
- package/dist/api/observable.d.ts +9 -15
- package/dist/core/atom.d.ts +1 -4
- package/dist/core/computedvalue.d.ts +5 -33
- package/dist/core/derivation.d.ts +1 -7
- package/dist/core/globalstate.d.ts +7 -2
- package/dist/core/observable.d.ts +9 -1
- package/dist/core/reaction.d.ts +1 -9
- package/dist/errors.d.ts +6 -4
- package/dist/internal.d.ts +1 -4
- package/dist/mobx.cjs.development.js +1704 -2484
- package/dist/mobx.cjs.development.js.map +1 -1
- package/dist/mobx.cjs.production.min.js +1 -1
- package/dist/mobx.cjs.production.min.js.map +1 -1
- package/dist/mobx.d.ts +2 -2
- package/dist/mobx.esm.development.js +1693 -2483
- package/dist/mobx.esm.development.js.map +1 -1
- package/dist/mobx.esm.js +1643 -2436
- package/dist/mobx.esm.js.map +1 -1
- package/dist/mobx.esm.production.min.js +1 -1
- package/dist/mobx.esm.production.min.js.map +1 -1
- package/dist/mobx.mjs +5308 -0
- package/dist/mobx.mjs.map +1 -0
- package/dist/mobx.umd.development.js +1707 -2487
- package/dist/mobx.umd.development.js.map +1 -1
- package/dist/mobx.umd.production.min.js +1 -1
- package/dist/mobx.umd.production.min.js.map +1 -1
- package/dist/types/actionannotation.d.ts +1 -0
- package/dist/types/computedannotation.d.ts +1 -0
- package/dist/types/decorator_fills.d.ts +2 -0
- package/dist/types/flowannotation.d.ts +1 -0
- package/dist/types/observableannotation.d.ts +5 -0
- package/dist/types/observablearray.d.ts +2 -5
- package/dist/types/observablemap.d.ts +1 -8
- package/dist/types/observableobject.d.ts +2 -13
- package/dist/types/observableset.d.ts +1 -3
- package/dist/types/observablevalue.d.ts +4 -6
- package/dist/types/overrideannotation.d.ts +1 -2
- package/dist/utils/comparer.d.ts +4 -11
- package/dist/utils/utils.d.ts +0 -2
- package/package.json +25 -15
- package/src/api/action.ts +27 -35
- package/src/api/annotation.ts +0 -1
- package/src/api/autorun.ts +2 -4
- package/src/api/computed.ts +21 -28
- package/src/api/configure.ts +1 -15
- package/src/api/decoratorannotation.ts +20 -0
- package/src/api/decorators.ts +1 -85
- package/src/api/extras.ts +1 -1
- package/src/api/flow.ts +26 -29
- package/src/api/intercept.ts +4 -3
- package/src/api/makeObservable.ts +45 -17
- package/src/api/object-api.ts +1 -1
- package/src/api/observable.ts +34 -67
- package/src/api/observe.ts +82 -3
- package/src/api/when.ts +4 -3
- package/src/core/action.ts +12 -5
- package/src/core/atom.ts +16 -14
- package/src/core/computedvalue.ts +36 -69
- package/src/core/derivation.ts +16 -15
- package/src/core/globalstate.ts +16 -13
- package/src/core/observable.ts +65 -73
- package/src/core/reaction.ts +19 -25
- package/src/core/spy.ts +3 -3
- package/src/errors.ts +23 -12
- package/src/internal.ts +1 -4
- package/src/mobx.ts +21 -10
- package/src/types/actionannotation.ts +5 -9
- package/src/types/autoannotation.ts +8 -11
- package/src/types/computedannotation.ts +13 -11
- package/src/types/decorator_fills.ts +4 -0
- package/src/types/dynamicobject.ts +0 -29
- package/src/types/flowannotation.ts +7 -4
- package/src/types/modifiers.ts +5 -0
- package/src/types/observableannotation.ts +6 -7
- package/src/types/observablearray.ts +8 -61
- package/src/types/observablemap.ts +4 -29
- package/src/types/observableobject.ts +5 -70
- package/src/types/observableset.ts +9 -52
- package/src/types/observablevalue.ts +7 -29
- package/src/types/overrideannotation.ts +7 -22
- package/src/types/type-utils.ts +4 -2
- package/src/utils/comparer.ts +4 -17
- package/src/utils/iterable.ts +3 -4
- package/src/utils/utils.ts +4 -46
- package/dist/api/trace.d.ts +0 -3
- package/dist/types/legacyobservablearray.d.ts +0 -14
- package/dist/utils/global.d.ts +0 -1
- package/src/api/trace.ts +0 -35
- package/src/types/legacyobservablearray.ts +0 -155
- package/src/utils/global.ts +0 -20
package/src/core/atom.ts
CHANGED
|
@@ -6,8 +6,6 @@ import {
|
|
|
6
6
|
endBatch,
|
|
7
7
|
getNextId,
|
|
8
8
|
noop,
|
|
9
|
-
onBecomeObserved,
|
|
10
|
-
onBecomeUnobserved,
|
|
11
9
|
propagateChanged,
|
|
12
10
|
reportObserved,
|
|
13
11
|
startBatch,
|
|
@@ -23,13 +21,17 @@ export interface IAtom extends IObservable {
|
|
|
23
21
|
reportChanged(): void
|
|
24
22
|
}
|
|
25
23
|
|
|
24
|
+
const enum AtomFlags {
|
|
25
|
+
isBeingObserved = 0b001,
|
|
26
|
+
isPendingUnobservation = 0b010,
|
|
27
|
+
diffValue = 0b100
|
|
28
|
+
}
|
|
29
|
+
|
|
26
30
|
export class Atom implements IAtom {
|
|
27
|
-
private static readonly isBeingObservedMask_ = 0b001
|
|
28
|
-
private static readonly isPendingUnobservationMask_ = 0b010
|
|
29
|
-
private static readonly diffValueMask_ = 0b100
|
|
30
31
|
private flags_ = 0b000
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
// Allocated lazily on first observer to save memory.
|
|
34
|
+
observers_: Set<IDerivation> | null = null
|
|
33
35
|
|
|
34
36
|
lastAccessedBy_ = 0
|
|
35
37
|
lowestObserverState_ = IDerivationState_.NOT_TRACKING_
|
|
@@ -41,24 +43,24 @@ export class Atom implements IAtom {
|
|
|
41
43
|
|
|
42
44
|
// for effective unobserving. BaseAtom has true, for extra optimization, so its onBecomeUnobserved never gets called, because it's not needed
|
|
43
45
|
get isBeingObserved(): boolean {
|
|
44
|
-
return getFlag(this.flags_,
|
|
46
|
+
return getFlag(this.flags_, AtomFlags.isBeingObserved)
|
|
45
47
|
}
|
|
46
48
|
set isBeingObserved(newValue: boolean) {
|
|
47
|
-
this.flags_ = setFlag(this.flags_,
|
|
49
|
+
this.flags_ = setFlag(this.flags_, AtomFlags.isBeingObserved, newValue)
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
get isPendingUnobservation(): boolean {
|
|
51
|
-
return getFlag(this.flags_,
|
|
53
|
+
return getFlag(this.flags_, AtomFlags.isPendingUnobservation)
|
|
52
54
|
}
|
|
53
55
|
set isPendingUnobservation(newValue: boolean) {
|
|
54
|
-
this.flags_ = setFlag(this.flags_,
|
|
56
|
+
this.flags_ = setFlag(this.flags_, AtomFlags.isPendingUnobservation, newValue)
|
|
55
57
|
}
|
|
56
58
|
|
|
57
59
|
get diffValue(): 0 | 1 {
|
|
58
|
-
return getFlag(this.flags_,
|
|
60
|
+
return getFlag(this.flags_, AtomFlags.diffValue) ? 1 : 0
|
|
59
61
|
}
|
|
60
62
|
set diffValue(newValue: 0 | 1) {
|
|
61
|
-
this.flags_ = setFlag(this.flags_,
|
|
63
|
+
this.flags_ = setFlag(this.flags_, AtomFlags.diffValue, newValue === 1 ? true : false)
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
// onBecomeObservedListeners
|
|
@@ -110,11 +112,11 @@ export function createAtom(
|
|
|
110
112
|
const atom = new Atom(name)
|
|
111
113
|
// default `noop` listener will not initialize the hook Set
|
|
112
114
|
if (onBecomeObservedHandler !== noop) {
|
|
113
|
-
|
|
115
|
+
atom.onBOL = new Set([onBecomeObservedHandler])
|
|
114
116
|
}
|
|
115
117
|
|
|
116
118
|
if (onBecomeUnobservedHandler !== noop) {
|
|
117
|
-
|
|
119
|
+
atom.onBUOL = new Set([onBecomeUnobservedHandler])
|
|
118
120
|
}
|
|
119
121
|
return atom
|
|
120
122
|
}
|
|
@@ -5,10 +5,8 @@ import {
|
|
|
5
5
|
IEqualsComparer,
|
|
6
6
|
IObservable,
|
|
7
7
|
Lambda,
|
|
8
|
-
TraceMode,
|
|
9
|
-
autorun,
|
|
10
8
|
clearObserving,
|
|
11
|
-
|
|
9
|
+
compareDefault,
|
|
12
10
|
createAction,
|
|
13
11
|
createInstanceofPredicate,
|
|
14
12
|
endBatch,
|
|
@@ -16,6 +14,7 @@ import {
|
|
|
16
14
|
globalState,
|
|
17
15
|
isCaughtException,
|
|
18
16
|
isSpyEnabled,
|
|
17
|
+
markObserved,
|
|
19
18
|
propagateChangeConfirmed,
|
|
20
19
|
propagateMaybeChanged,
|
|
21
20
|
reportObserved,
|
|
@@ -24,9 +23,6 @@ import {
|
|
|
24
23
|
startBatch,
|
|
25
24
|
toPrimitive,
|
|
26
25
|
trackDerivedFunction,
|
|
27
|
-
untrackedEnd,
|
|
28
|
-
untrackedStart,
|
|
29
|
-
UPDATE,
|
|
30
26
|
die,
|
|
31
27
|
allowStateChangesStart,
|
|
32
28
|
allowStateChangesEnd
|
|
@@ -77,11 +73,20 @@ export type IComputedDidChange<T = any> = {
|
|
|
77
73
|
*
|
|
78
74
|
* If at any point it's outside batch and it isn't observed: reset everything and go to 1.
|
|
79
75
|
*/
|
|
76
|
+
const enum ComputedValueFlags {
|
|
77
|
+
isComputing = 0b00001,
|
|
78
|
+
isRunningSetter = 0b00010,
|
|
79
|
+
isBeingObserved = 0b00100,
|
|
80
|
+
isPendingUnobservation = 0b01000,
|
|
81
|
+
diffValue = 0b10000
|
|
82
|
+
}
|
|
83
|
+
|
|
80
84
|
export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDerivation {
|
|
81
85
|
dependenciesState_ = IDerivationState_.NOT_TRACKING_
|
|
82
86
|
observing_: IObservable[] = [] // nodes we are looking at. Our value depends on these nodes
|
|
83
87
|
newObserving_ = null // during tracking it's an array with new observed observers
|
|
84
|
-
|
|
88
|
+
// Lazily allocated on first observer - see Atom.observers_.
|
|
89
|
+
observers_: Set<IDerivation> | null = null
|
|
85
90
|
runId_ = 0
|
|
86
91
|
lastAccessedBy_ = 0
|
|
87
92
|
lowestObserverState_ = IDerivationState_.UP_TO_DATE_
|
|
@@ -90,16 +95,10 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
|
|
|
90
95
|
name_: string
|
|
91
96
|
triggeredBy_?: string
|
|
92
97
|
|
|
93
|
-
private static readonly isComputingMask_ = 0b00001
|
|
94
|
-
private static readonly isRunningSetterMask_ = 0b00010
|
|
95
|
-
private static readonly isBeingObservedMask_ = 0b00100
|
|
96
|
-
private static readonly isPendingUnobservationMask_ = 0b01000
|
|
97
|
-
private static readonly diffValueMask_ = 0b10000
|
|
98
98
|
private flags_ = 0b00000
|
|
99
99
|
|
|
100
100
|
derivation: () => T // N.B: unminified as it is used by MST
|
|
101
101
|
setter_?: (value: T) => void
|
|
102
|
-
isTracing_: TraceMode = TraceMode.NONE
|
|
103
102
|
scope_: Object | undefined
|
|
104
103
|
private equals_: IEqualsComparer<any>
|
|
105
104
|
private requiresReaction_: boolean | undefined
|
|
@@ -110,11 +109,9 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
|
|
|
110
109
|
*
|
|
111
110
|
* The `name` property is for debug purposes only.
|
|
112
111
|
*
|
|
113
|
-
* The `equals` property specifies the comparer function
|
|
114
|
-
* value differs from the previous value.
|
|
115
|
-
*
|
|
116
|
-
* Structural comparison can be convenient if you always produce a new aggregated object and
|
|
117
|
-
* don't want to notify observers if it is structurally the same.
|
|
112
|
+
* The `equals` property specifies the comparer function used to determine if a newly produced
|
|
113
|
+
* value differs from the previous value. Structural comparison can be convenient if you always
|
|
114
|
+
* produce a new aggregated object and don't want to notify observers if it is structurally the same.
|
|
118
115
|
* This is useful for working with vectors, mouse coordinates etc.
|
|
119
116
|
*/
|
|
120
117
|
constructor(options: IComputedValueOptions<T>) {
|
|
@@ -129,11 +126,7 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
|
|
|
129
126
|
options.set
|
|
130
127
|
) as any
|
|
131
128
|
}
|
|
132
|
-
this.equals_ =
|
|
133
|
-
options.equals ||
|
|
134
|
-
((options as any).compareStructural || (options as any).struct
|
|
135
|
-
? comparer.structural
|
|
136
|
-
: comparer.default)
|
|
129
|
+
this.equals_ = options.equals || compareDefault
|
|
137
130
|
this.scope_ = options.context
|
|
138
131
|
this.requiresReaction_ = options.requiresReaction
|
|
139
132
|
this.keepAlive_ = !!options.keepAlive
|
|
@@ -160,40 +153,40 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
|
|
|
160
153
|
|
|
161
154
|
// to check for cycles
|
|
162
155
|
private get isComputing(): boolean {
|
|
163
|
-
return getFlag(this.flags_,
|
|
156
|
+
return getFlag(this.flags_, ComputedValueFlags.isComputing)
|
|
164
157
|
}
|
|
165
158
|
private set isComputing(newValue: boolean) {
|
|
166
|
-
this.flags_ = setFlag(this.flags_,
|
|
159
|
+
this.flags_ = setFlag(this.flags_, ComputedValueFlags.isComputing, newValue)
|
|
167
160
|
}
|
|
168
161
|
|
|
169
162
|
private get isRunningSetter(): boolean {
|
|
170
|
-
return getFlag(this.flags_,
|
|
163
|
+
return getFlag(this.flags_, ComputedValueFlags.isRunningSetter)
|
|
171
164
|
}
|
|
172
165
|
private set isRunningSetter(newValue: boolean) {
|
|
173
|
-
this.flags_ = setFlag(this.flags_,
|
|
166
|
+
this.flags_ = setFlag(this.flags_, ComputedValueFlags.isRunningSetter, newValue)
|
|
174
167
|
}
|
|
175
168
|
|
|
176
169
|
get isBeingObserved(): boolean {
|
|
177
|
-
return getFlag(this.flags_,
|
|
170
|
+
return getFlag(this.flags_, ComputedValueFlags.isBeingObserved)
|
|
178
171
|
}
|
|
179
172
|
set isBeingObserved(newValue: boolean) {
|
|
180
|
-
this.flags_ = setFlag(this.flags_,
|
|
173
|
+
this.flags_ = setFlag(this.flags_, ComputedValueFlags.isBeingObserved, newValue)
|
|
181
174
|
}
|
|
182
175
|
|
|
183
176
|
get isPendingUnobservation(): boolean {
|
|
184
|
-
return getFlag(this.flags_,
|
|
177
|
+
return getFlag(this.flags_, ComputedValueFlags.isPendingUnobservation)
|
|
185
178
|
}
|
|
186
179
|
set isPendingUnobservation(newValue: boolean) {
|
|
187
|
-
this.flags_ = setFlag(this.flags_,
|
|
180
|
+
this.flags_ = setFlag(this.flags_, ComputedValueFlags.isPendingUnobservation, newValue)
|
|
188
181
|
}
|
|
189
182
|
|
|
190
183
|
get diffValue(): 0 | 1 {
|
|
191
|
-
return getFlag(this.flags_,
|
|
184
|
+
return getFlag(this.flags_, ComputedValueFlags.diffValue) ? 1 : 0
|
|
192
185
|
}
|
|
193
186
|
set diffValue(newValue: 0 | 1) {
|
|
194
187
|
this.flags_ = setFlag(
|
|
195
188
|
this.flags_,
|
|
196
|
-
|
|
189
|
+
ComputedValueFlags.diffValue,
|
|
197
190
|
newValue === 1 ? true : false
|
|
198
191
|
)
|
|
199
192
|
}
|
|
@@ -209,7 +202,7 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
|
|
|
209
202
|
if (
|
|
210
203
|
globalState.inBatch === 0 &&
|
|
211
204
|
// !globalState.trackingDerivatpion &&
|
|
212
|
-
this.observers_.size === 0 &&
|
|
205
|
+
(!this.observers_ || this.observers_.size === 0) &&
|
|
213
206
|
!this.keepAlive_
|
|
214
207
|
) {
|
|
215
208
|
if (shouldCompute(this)) {
|
|
@@ -219,6 +212,7 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
|
|
|
219
212
|
endBatch()
|
|
220
213
|
}
|
|
221
214
|
} else {
|
|
215
|
+
const wasBeingObserved = this.isBeingObserved
|
|
222
216
|
reportObserved(this)
|
|
223
217
|
if (shouldCompute(this)) {
|
|
224
218
|
let prevTrackingContext = globalState.trackingContext
|
|
@@ -229,6 +223,10 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
|
|
|
229
223
|
propagateChangeConfirmed(this)
|
|
230
224
|
}
|
|
231
225
|
globalState.trackingContext = prevTrackingContext
|
|
226
|
+
} else if (!wasBeingObserved && this.isBeingObserved) {
|
|
227
|
+
// We just became observed while serving a cached value, so the getter
|
|
228
|
+
// won't run and won't re-report our dependencies. Cascade to them. #4547
|
|
229
|
+
this.observing_.forEach(markObserved)
|
|
232
230
|
}
|
|
233
231
|
}
|
|
234
232
|
const result = this.value_!
|
|
@@ -289,7 +287,7 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
|
|
|
289
287
|
computeValue_(track: boolean) {
|
|
290
288
|
this.isComputing = true
|
|
291
289
|
// don't allow state changes during computation
|
|
292
|
-
const prev = allowStateChangesStart(false)
|
|
290
|
+
const prev = __DEV__ ? allowStateChangesStart(false) : false
|
|
293
291
|
let res: T | CaughtException
|
|
294
292
|
if (track) {
|
|
295
293
|
res = trackDerivedFunction(this, this.derivation, this.scope_)
|
|
@@ -304,7 +302,9 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
|
|
|
304
302
|
}
|
|
305
303
|
}
|
|
306
304
|
}
|
|
307
|
-
|
|
305
|
+
if (__DEV__) {
|
|
306
|
+
allowStateChangesEnd(prev)
|
|
307
|
+
}
|
|
308
308
|
this.isComputing = false
|
|
309
309
|
return res
|
|
310
310
|
}
|
|
@@ -313,46 +313,13 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
|
|
|
313
313
|
if (!this.keepAlive_) {
|
|
314
314
|
clearObserving(this)
|
|
315
315
|
this.value_ = undefined // don't hold on to computed value!
|
|
316
|
-
if (__DEV__ && this.isTracing_ !== TraceMode.NONE) {
|
|
317
|
-
console.log(
|
|
318
|
-
`[mobx.trace] Computed value '${this.name_}' was suspended and it will recompute on the next access.`
|
|
319
|
-
)
|
|
320
|
-
}
|
|
321
316
|
}
|
|
322
317
|
}
|
|
323
318
|
|
|
324
|
-
observe_(listener: (change: IComputedDidChange<T>) => void, fireImmediately?: boolean): Lambda {
|
|
325
|
-
let firstTime = true
|
|
326
|
-
let prevValue: T | undefined = undefined
|
|
327
|
-
return autorun(() => {
|
|
328
|
-
// TODO: why is this in a different place than the spyReport() function? in all other observables it's called in the same place
|
|
329
|
-
let newValue = this.get()
|
|
330
|
-
if (!firstTime || fireImmediately) {
|
|
331
|
-
const prevU = untrackedStart()
|
|
332
|
-
listener({
|
|
333
|
-
observableKind: "computed",
|
|
334
|
-
debugObjectName: this.name_,
|
|
335
|
-
type: UPDATE,
|
|
336
|
-
object: this,
|
|
337
|
-
newValue,
|
|
338
|
-
oldValue: prevValue
|
|
339
|
-
})
|
|
340
|
-
untrackedEnd(prevU)
|
|
341
|
-
}
|
|
342
|
-
firstTime = false
|
|
343
|
-
prevValue = newValue
|
|
344
|
-
})
|
|
345
|
-
}
|
|
346
|
-
|
|
347
319
|
warnAboutUntrackedRead_() {
|
|
348
320
|
if (!__DEV__) {
|
|
349
321
|
return
|
|
350
322
|
}
|
|
351
|
-
if (this.isTracing_ !== TraceMode.NONE) {
|
|
352
|
-
console.log(
|
|
353
|
-
`[mobx.trace] Computed value '${this.name_}' is being read outside a reactive context. Doing a full recompute.`
|
|
354
|
-
)
|
|
355
|
-
}
|
|
356
323
|
if (
|
|
357
324
|
typeof this.requiresReaction_ === "boolean"
|
|
358
325
|
? this.requiresReaction_
|
package/src/core/derivation.ts
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
removeObserver
|
|
9
9
|
} from "../internal"
|
|
10
10
|
|
|
11
|
-
export enum IDerivationState_ {
|
|
11
|
+
export const enum IDerivationState_ {
|
|
12
12
|
// before being run or (outside batch and not being observed)
|
|
13
13
|
// at this point derivation is not holding any data about dependency tree
|
|
14
14
|
NOT_TRACKING_ = -1,
|
|
@@ -28,12 +28,6 @@ export enum IDerivationState_ {
|
|
|
28
28
|
STALE_ = 2
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
export enum TraceMode {
|
|
32
|
-
NONE,
|
|
33
|
-
LOG,
|
|
34
|
-
BREAK
|
|
35
|
-
}
|
|
36
|
-
|
|
37
31
|
/**
|
|
38
32
|
* A derivation is everything that can be derived from the state (all the atoms) in a pure manner.
|
|
39
33
|
* See https://medium.com/@mweststrate/becoming-fully-reactive-an-in-depth-explanation-of-mobservable-55995262a254#.xvbh6qd74
|
|
@@ -52,7 +46,6 @@ export interface IDerivation extends IDepTreeNode {
|
|
|
52
46
|
*/
|
|
53
47
|
unboundDepsCount_: number
|
|
54
48
|
onBecomeStale_(): void
|
|
55
|
-
isTracing_: TraceMode
|
|
56
49
|
|
|
57
50
|
/**
|
|
58
51
|
* warn if the derivation has no dependencies after creation/update
|
|
@@ -90,7 +83,7 @@ export function shouldCompute(derivation: IDerivation): boolean {
|
|
|
90
83
|
return true
|
|
91
84
|
case IDerivationState_.POSSIBLY_STALE_: {
|
|
92
85
|
// state propagation can occur outside of action/reactive context #2195
|
|
93
|
-
const prevAllowStateReads = allowStateReadsStart(true)
|
|
86
|
+
const prevAllowStateReads = __DEV__ ? allowStateReadsStart(true) : true
|
|
94
87
|
const prevUntracked = untrackedStart() // no need for those computeds to be reported, they will be picked up in trackDerivedFunction.
|
|
95
88
|
const obs = derivation.observing_,
|
|
96
89
|
l = obs.length
|
|
@@ -105,7 +98,9 @@ export function shouldCompute(derivation: IDerivation): boolean {
|
|
|
105
98
|
} catch (e) {
|
|
106
99
|
// we are not interested in the value *or* exception at this moment, but if there is one, notify all
|
|
107
100
|
untrackedEnd(prevUntracked)
|
|
108
|
-
|
|
101
|
+
if (__DEV__) {
|
|
102
|
+
allowStateReadsEnd(prevAllowStateReads)
|
|
103
|
+
}
|
|
109
104
|
return true
|
|
110
105
|
}
|
|
111
106
|
}
|
|
@@ -114,14 +109,18 @@ export function shouldCompute(derivation: IDerivation): boolean {
|
|
|
114
109
|
// invariantShouldCompute(derivation)
|
|
115
110
|
if ((derivation.dependenciesState_ as any) === IDerivationState_.STALE_) {
|
|
116
111
|
untrackedEnd(prevUntracked)
|
|
117
|
-
|
|
112
|
+
if (__DEV__) {
|
|
113
|
+
allowStateReadsEnd(prevAllowStateReads)
|
|
114
|
+
}
|
|
118
115
|
return true
|
|
119
116
|
}
|
|
120
117
|
}
|
|
121
118
|
}
|
|
122
119
|
changeDependenciesStateTo0(derivation)
|
|
123
120
|
untrackedEnd(prevUntracked)
|
|
124
|
-
|
|
121
|
+
if (__DEV__) {
|
|
122
|
+
allowStateReadsEnd(prevAllowStateReads)
|
|
123
|
+
}
|
|
125
124
|
return false
|
|
126
125
|
}
|
|
127
126
|
}
|
|
@@ -135,7 +134,7 @@ export function checkIfStateModificationsAreAllowed(atom: IAtom) {
|
|
|
135
134
|
if (!__DEV__) {
|
|
136
135
|
return
|
|
137
136
|
}
|
|
138
|
-
const hasObservers = atom.observers_.size > 0
|
|
137
|
+
const hasObservers = !!atom.observers_ && atom.observers_.size > 0
|
|
139
138
|
// Should not be possible to change observed state outside strict mode, except during initialization, see #563
|
|
140
139
|
if (
|
|
141
140
|
!globalState.allowStateChanges &&
|
|
@@ -165,7 +164,7 @@ export function checkIfStateReadsAreAllowed(observable: IObservable) {
|
|
|
165
164
|
* as observer of any of the accessed observables.
|
|
166
165
|
*/
|
|
167
166
|
export function trackDerivedFunction<T>(derivation: IDerivation, f: () => T, context: any) {
|
|
168
|
-
const prevAllowStateReads = allowStateReadsStart(true)
|
|
167
|
+
const prevAllowStateReads = __DEV__ ? allowStateReadsStart(true) : true
|
|
169
168
|
changeDependenciesStateTo0(derivation)
|
|
170
169
|
// Preallocate array; will be trimmed by bindDependencies.
|
|
171
170
|
derivation.newObserving_ = new Array(
|
|
@@ -193,7 +192,9 @@ export function trackDerivedFunction<T>(derivation: IDerivation, f: () => T, con
|
|
|
193
192
|
bindDependencies(derivation)
|
|
194
193
|
|
|
195
194
|
warnAboutDerivationWithoutDependencies(derivation)
|
|
196
|
-
|
|
195
|
+
if (__DEV__) {
|
|
196
|
+
allowStateReadsEnd(prevAllowStateReads)
|
|
197
|
+
}
|
|
197
198
|
return result
|
|
198
199
|
}
|
|
199
200
|
|
package/src/core/globalstate.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { IDerivation, IObservable, Reaction, die
|
|
1
|
+
import { IDerivation, IObservable, Reaction, die } from "../internal"
|
|
2
2
|
import { ComputedValue } from "./computedvalue"
|
|
3
3
|
|
|
4
|
+
const MOBX_GLOBALS_VERSION = 7
|
|
5
|
+
|
|
4
6
|
/**
|
|
5
7
|
* These values will persist if global state is reset
|
|
6
8
|
*/
|
|
@@ -14,8 +16,7 @@ const persistentKeys: (keyof MobXGlobals)[] = [
|
|
|
14
16
|
"allowStateReads",
|
|
15
17
|
"disableErrorBoundaries",
|
|
16
18
|
"runId",
|
|
17
|
-
"UNCHANGED"
|
|
18
|
-
"useProxies"
|
|
19
|
+
"UNCHANGED"
|
|
19
20
|
]
|
|
20
21
|
|
|
21
22
|
export type IUNCHANGED = {}
|
|
@@ -29,7 +30,7 @@ export class MobXGlobals {
|
|
|
29
30
|
* N.B: this version is unrelated to the package version of MobX, and is only the version of the
|
|
30
31
|
* internal state storage of MobX, and can be the same across many different package versions
|
|
31
32
|
*/
|
|
32
|
-
version =
|
|
33
|
+
version = MOBX_GLOBALS_VERSION
|
|
33
34
|
|
|
34
35
|
/**
|
|
35
36
|
* globally unique token to signal unchanged
|
|
@@ -81,6 +82,14 @@ export class MobXGlobals {
|
|
|
81
82
|
*/
|
|
82
83
|
isRunningReactions = false
|
|
83
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Are we currently draining pendingUnobservations in endBatch?
|
|
87
|
+
* An onBecomeUnobserved handler can dispose a Reaction, which calls
|
|
88
|
+
* startBatch/endBatch again; this guards against re-entering the same
|
|
89
|
+
* drain loop recursively (see endBatch in observable.ts).
|
|
90
|
+
*/
|
|
91
|
+
isRunningUnobservations = false
|
|
92
|
+
|
|
84
93
|
/**
|
|
85
94
|
* Is it allowed to change observables at this point?
|
|
86
95
|
* In general, MobX doesn't allow that when running computations and React.render.
|
|
@@ -138,12 +147,6 @@ export class MobXGlobals {
|
|
|
138
147
|
*/
|
|
139
148
|
suppressReactionErrors = false
|
|
140
149
|
|
|
141
|
-
useProxies = true
|
|
142
|
-
/*
|
|
143
|
-
* print warnings about code that would fail if proxies weren't available
|
|
144
|
-
*/
|
|
145
|
-
verifyProxies = false
|
|
146
|
-
|
|
147
150
|
/**
|
|
148
151
|
* False forces all object's descriptors to
|
|
149
152
|
* writable: true
|
|
@@ -156,11 +159,11 @@ let canMergeGlobalState = true
|
|
|
156
159
|
let isolateCalled = false
|
|
157
160
|
|
|
158
161
|
export let globalState: MobXGlobals = (function () {
|
|
159
|
-
let global =
|
|
162
|
+
let global = globalThis as any
|
|
160
163
|
if (global.__mobxInstanceCount > 0 && !global.__mobxGlobals) {
|
|
161
164
|
canMergeGlobalState = false
|
|
162
165
|
}
|
|
163
|
-
if (global.__mobxGlobals && global.__mobxGlobals.version !==
|
|
166
|
+
if (global.__mobxGlobals && global.__mobxGlobals.version !== MOBX_GLOBALS_VERSION) {
|
|
164
167
|
canMergeGlobalState = false
|
|
165
168
|
}
|
|
166
169
|
|
|
@@ -195,7 +198,7 @@ export function isolateGlobalState() {
|
|
|
195
198
|
}
|
|
196
199
|
isolateCalled = true
|
|
197
200
|
if (canMergeGlobalState) {
|
|
198
|
-
let global =
|
|
201
|
+
let global = globalThis as any
|
|
199
202
|
if (--global.__mobxInstanceCount === 0) {
|
|
200
203
|
global.__mobxGlobals = undefined
|
|
201
204
|
}
|