mobx 6.1.8 → 6.9.0
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 +224 -7
- package/README.md +54 -52
- package/dist/api/annotation.d.ts +6 -12
- package/dist/api/autorun.d.ts +4 -4
- package/dist/api/flow.d.ts +1 -0
- package/dist/api/intercept.d.ts +5 -5
- package/dist/api/object-api.d.ts +2 -0
- package/dist/api/observable.d.ts +5 -1
- package/dist/api/observe.d.ts +4 -4
- package/dist/api/tojs.d.ts +4 -1
- package/dist/api/when.d.ts +8 -0
- package/dist/core/atom.d.ts +1 -1
- package/dist/core/computedvalue.d.ts +0 -1
- package/dist/core/globalstate.d.ts +4 -0
- package/dist/core/reaction.d.ts +2 -2
- package/dist/errors.d.ts +4 -2
- package/dist/internal.d.ts +1 -0
- package/dist/mobx.cjs.development.js +1477 -1719
- 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 +1 -1
- package/dist/mobx.esm.development.js +1475 -1720
- package/dist/mobx.esm.development.js.map +1 -1
- package/dist/mobx.esm.js +1492 -1726
- 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.umd.development.js +1477 -1719
- 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 +7 -1
- package/dist/types/autoannotation.d.ts +3 -0
- package/dist/types/observablemap.d.ts +5 -4
- package/dist/types/observableobject.d.ts +6 -9
- package/dist/types/observableset.d.ts +4 -4
- package/dist/types/observablevalue.d.ts +3 -5
- package/dist/utils/utils.d.ts +4 -4
- package/package.json +1 -1
- package/src/api/action.ts +8 -3
- package/src/api/annotation.ts +14 -44
- package/src/api/autorun.ts +38 -17
- package/src/api/computed.ts +5 -2
- package/src/api/configure.ts +6 -2
- package/src/api/decorators.ts +1 -1
- package/src/api/extendobservable.ts +12 -6
- package/src/api/extras.ts +4 -2
- package/src/api/flow.ts +17 -5
- package/src/api/intercept-read.ts +4 -2
- package/src/api/intercept.ts +10 -7
- package/src/api/iscomputed.ts +14 -8
- package/src/api/isobservable.ts +10 -4
- package/src/api/makeObservable.ts +35 -36
- package/src/api/object-api.ts +42 -14
- package/src/api/observable.ts +39 -25
- package/src/api/observe.ts +9 -6
- package/src/api/tojs.ts +20 -10
- package/src/api/trace.ts +6 -2
- package/src/api/when.ts +34 -9
- package/src/core/action.ts +11 -5
- package/src/core/atom.ts +9 -2
- package/src/core/computedvalue.ts +48 -27
- package/src/core/derivation.ts +34 -12
- package/src/core/globalstate.ts +25 -7
- package/src/core/observable.ts +23 -13
- package/src/core/reaction.ts +16 -7
- package/src/core/spy.ts +20 -7
- package/src/errors.ts +16 -3
- package/src/internal.ts +1 -0
- package/src/mobx.ts +6 -2
- package/src/types/actionannotation.ts +30 -52
- package/src/types/autoannotation.ts +107 -0
- package/src/types/computedannotation.ts +7 -37
- package/src/types/dynamicobject.ts +12 -6
- package/src/types/flowannotation.ts +40 -41
- package/src/types/intercept-utils.ts +9 -3
- package/src/types/legacyobservablearray.ts +26 -3
- package/src/types/listen-utils.ts +6 -2
- package/src/types/modifiers.ts +52 -16
- package/src/types/observableannotation.ts +7 -34
- package/src/types/observablearray.ts +106 -45
- package/src/types/observablemap.ts +71 -35
- package/src/types/observableobject.ts +88 -82
- package/src/types/observableset.ts +32 -13
- package/src/types/observablevalue.ts +16 -10
- package/src/types/overrideannotation.ts +4 -2
- package/src/types/type-utils.ts +34 -12
- package/src/utils/comparer.ts +5 -1
- package/src/utils/eq.ts +45 -15
- package/src/utils/utils.ts +39 -16
package/src/core/action.ts
CHANGED
|
@@ -14,7 +14,8 @@ import {
|
|
|
14
14
|
ACTION,
|
|
15
15
|
EMPTY_ARRAY,
|
|
16
16
|
die,
|
|
17
|
-
getDescriptor
|
|
17
|
+
getDescriptor,
|
|
18
|
+
defineProperty
|
|
18
19
|
} from "../internal"
|
|
19
20
|
|
|
20
21
|
// we don't use globalState for these in order to avoid possible issues with multiple
|
|
@@ -38,9 +39,12 @@ export function createAction(
|
|
|
38
39
|
ref?: Object
|
|
39
40
|
): Function {
|
|
40
41
|
if (__DEV__) {
|
|
41
|
-
if (!isFunction(fn))
|
|
42
|
-
|
|
42
|
+
if (!isFunction(fn)) {
|
|
43
|
+
die("`action` can only be invoked on functions")
|
|
44
|
+
}
|
|
45
|
+
if (typeof actionName !== "string" || !actionName) {
|
|
43
46
|
die(`actions should have valid names, got: '${actionName}'`)
|
|
47
|
+
}
|
|
44
48
|
}
|
|
45
49
|
function res() {
|
|
46
50
|
return executeAction(actionName, autoAction, fn, ref || this, arguments)
|
|
@@ -48,7 +52,7 @@ export function createAction(
|
|
|
48
52
|
res.isMobxAction = true
|
|
49
53
|
if (isFunctionNameConfigurable) {
|
|
50
54
|
tmpNameDescriptor.value = actionName
|
|
51
|
-
|
|
55
|
+
defineProperty(res, "name", tmpNameDescriptor)
|
|
52
56
|
}
|
|
53
57
|
return res
|
|
54
58
|
}
|
|
@@ -136,7 +140,9 @@ export function _endAction(runInfo: IActionRunInfo) {
|
|
|
136
140
|
allowStateChangesEnd(runInfo.prevAllowStateChanges_)
|
|
137
141
|
allowStateReadsEnd(runInfo.prevAllowStateReads_)
|
|
138
142
|
endBatch()
|
|
139
|
-
if (runInfo.runAsAction_)
|
|
143
|
+
if (runInfo.runAsAction_) {
|
|
144
|
+
untrackedEnd(runInfo.prevDerivation_)
|
|
145
|
+
}
|
|
140
146
|
if (__DEV__ && runInfo.notifySpy_) {
|
|
141
147
|
spyReportEnd({ time: Date.now() - runInfo.startTime_ })
|
|
142
148
|
}
|
package/src/core/atom.ts
CHANGED
|
@@ -11,13 +11,14 @@ import {
|
|
|
11
11
|
propagateChanged,
|
|
12
12
|
reportObserved,
|
|
13
13
|
startBatch,
|
|
14
|
-
Lambda
|
|
14
|
+
Lambda,
|
|
15
|
+
globalState
|
|
15
16
|
} from "../internal"
|
|
16
17
|
|
|
17
18
|
export const $mobx = Symbol("mobx administration")
|
|
18
19
|
|
|
19
20
|
export interface IAtom extends IObservable {
|
|
20
|
-
reportObserved()
|
|
21
|
+
reportObserved(): boolean
|
|
21
22
|
reportChanged()
|
|
22
23
|
}
|
|
23
24
|
|
|
@@ -66,6 +67,12 @@ export class Atom implements IAtom {
|
|
|
66
67
|
public reportChanged() {
|
|
67
68
|
startBatch()
|
|
68
69
|
propagateChanged(this)
|
|
70
|
+
// We could update state version only at the end of batch,
|
|
71
|
+
// but we would still have to switch some global flag here to signal a change.
|
|
72
|
+
globalState.stateVersion =
|
|
73
|
+
globalState.stateVersion < Number.MAX_SAFE_INTEGER
|
|
74
|
+
? globalState.stateVersion + 1
|
|
75
|
+
: Number.MIN_SAFE_INTEGER
|
|
69
76
|
endBatch()
|
|
70
77
|
}
|
|
71
78
|
|
|
@@ -35,7 +35,6 @@ import {
|
|
|
35
35
|
export interface IComputedValue<T> {
|
|
36
36
|
get(): T
|
|
37
37
|
set(value: T): void
|
|
38
|
-
observe_(listener: (change: IComputedDidChange<T>) => void, fireImmediately?: boolean): Lambda
|
|
39
38
|
}
|
|
40
39
|
|
|
41
40
|
export interface IComputedValueOptions<T> {
|
|
@@ -98,7 +97,7 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
|
|
|
98
97
|
isTracing_: TraceMode = TraceMode.NONE
|
|
99
98
|
scope_: Object | undefined
|
|
100
99
|
private equals_: IEqualsComparer<any>
|
|
101
|
-
private requiresReaction_: boolean
|
|
100
|
+
private requiresReaction_: boolean | undefined
|
|
102
101
|
keepAlive_: boolean
|
|
103
102
|
|
|
104
103
|
/**
|
|
@@ -114,7 +113,9 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
|
|
|
114
113
|
* This is useful for working with vectors, mouse coordinates etc.
|
|
115
114
|
*/
|
|
116
115
|
constructor(options: IComputedValueOptions<T>) {
|
|
117
|
-
if (!options.get)
|
|
116
|
+
if (!options.get) {
|
|
117
|
+
die(31)
|
|
118
|
+
}
|
|
118
119
|
this.derivation = options.get!
|
|
119
120
|
this.name_ = options.name || (__DEV__ ? "ComputedValue@" + getNextId() : "ComputedValue")
|
|
120
121
|
if (options.set) {
|
|
@@ -129,7 +130,7 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
|
|
|
129
130
|
? comparer.structural
|
|
130
131
|
: comparer.default)
|
|
131
132
|
this.scope_ = options.context
|
|
132
|
-
this.requiresReaction_ =
|
|
133
|
+
this.requiresReaction_ = options.requiresReaction
|
|
133
134
|
this.keepAlive_ = !!options.keepAlive
|
|
134
135
|
}
|
|
135
136
|
|
|
@@ -157,7 +158,9 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
|
|
|
157
158
|
* Will evaluate its computation first if needed.
|
|
158
159
|
*/
|
|
159
160
|
public get(): T {
|
|
160
|
-
if (this.isComputing_)
|
|
161
|
+
if (this.isComputing_) {
|
|
162
|
+
die(32, this.name_, this.derivation)
|
|
163
|
+
}
|
|
161
164
|
if (
|
|
162
165
|
globalState.inBatch === 0 &&
|
|
163
166
|
// !globalState.trackingDerivatpion &&
|
|
@@ -174,27 +177,37 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
|
|
|
174
177
|
reportObserved(this)
|
|
175
178
|
if (shouldCompute(this)) {
|
|
176
179
|
let prevTrackingContext = globalState.trackingContext
|
|
177
|
-
if (this.keepAlive_ && !prevTrackingContext)
|
|
178
|
-
|
|
180
|
+
if (this.keepAlive_ && !prevTrackingContext) {
|
|
181
|
+
globalState.trackingContext = this
|
|
182
|
+
}
|
|
183
|
+
if (this.trackAndCompute()) {
|
|
184
|
+
propagateChangeConfirmed(this)
|
|
185
|
+
}
|
|
179
186
|
globalState.trackingContext = prevTrackingContext
|
|
180
187
|
}
|
|
181
188
|
}
|
|
182
189
|
const result = this.value_!
|
|
183
190
|
|
|
184
|
-
if (isCaughtException(result))
|
|
191
|
+
if (isCaughtException(result)) {
|
|
192
|
+
throw result.cause
|
|
193
|
+
}
|
|
185
194
|
return result
|
|
186
195
|
}
|
|
187
196
|
|
|
188
197
|
public set(value: T) {
|
|
189
198
|
if (this.setter_) {
|
|
190
|
-
if (this.isRunningSetter_)
|
|
199
|
+
if (this.isRunningSetter_) {
|
|
200
|
+
die(33, this.name_)
|
|
201
|
+
}
|
|
191
202
|
this.isRunningSetter_ = true
|
|
192
203
|
try {
|
|
193
204
|
this.setter_.call(this.scope_, value)
|
|
194
205
|
} finally {
|
|
195
206
|
this.isRunningSetter_ = false
|
|
196
207
|
}
|
|
197
|
-
} else
|
|
208
|
+
} else {
|
|
209
|
+
die(34, this.name_)
|
|
210
|
+
}
|
|
198
211
|
}
|
|
199
212
|
|
|
200
213
|
trackAndCompute(): boolean {
|
|
@@ -204,17 +217,6 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
|
|
|
204
217
|
/* see #1208 */ this.dependenciesState_ === IDerivationState_.NOT_TRACKING_
|
|
205
218
|
const newValue = this.computeValue_(true)
|
|
206
219
|
|
|
207
|
-
if (__DEV__ && isSpyEnabled()) {
|
|
208
|
-
spyReport({
|
|
209
|
-
observableKind: "computed",
|
|
210
|
-
debugObjectName: this.name_,
|
|
211
|
-
object: this.scope_,
|
|
212
|
-
type: "update",
|
|
213
|
-
oldValue: this.value_,
|
|
214
|
-
newValue
|
|
215
|
-
} as IComputedDidChange)
|
|
216
|
-
}
|
|
217
|
-
|
|
218
220
|
const changed =
|
|
219
221
|
wasSuspended ||
|
|
220
222
|
isCaughtException(oldValue) ||
|
|
@@ -223,6 +225,17 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
|
|
|
223
225
|
|
|
224
226
|
if (changed) {
|
|
225
227
|
this.value_ = newValue
|
|
228
|
+
|
|
229
|
+
if (__DEV__ && isSpyEnabled()) {
|
|
230
|
+
spyReport({
|
|
231
|
+
observableKind: "computed",
|
|
232
|
+
debugObjectName: this.name_,
|
|
233
|
+
object: this.scope_,
|
|
234
|
+
type: "update",
|
|
235
|
+
oldValue,
|
|
236
|
+
newValue
|
|
237
|
+
} as IComputedDidChange)
|
|
238
|
+
}
|
|
226
239
|
}
|
|
227
240
|
|
|
228
241
|
return changed
|
|
@@ -255,6 +268,11 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
|
|
|
255
268
|
if (!this.keepAlive_) {
|
|
256
269
|
clearObserving(this)
|
|
257
270
|
this.value_ = undefined // don't hold on to computed value!
|
|
271
|
+
if (__DEV__ && this.isTracing_ !== TraceMode.NONE) {
|
|
272
|
+
console.log(
|
|
273
|
+
`[mobx.trace] Computed value '${this.name_}' was suspended and it will recompute on the next access.`
|
|
274
|
+
)
|
|
275
|
+
}
|
|
258
276
|
}
|
|
259
277
|
}
|
|
260
278
|
|
|
@@ -282,18 +300,21 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
|
|
|
282
300
|
}
|
|
283
301
|
|
|
284
302
|
warnAboutUntrackedRead_() {
|
|
285
|
-
if (!__DEV__)
|
|
286
|
-
|
|
287
|
-
die(`[mobx] Computed value ${this.name_} is read outside a reactive context`)
|
|
303
|
+
if (!__DEV__) {
|
|
304
|
+
return
|
|
288
305
|
}
|
|
289
306
|
if (this.isTracing_ !== TraceMode.NONE) {
|
|
290
307
|
console.log(
|
|
291
|
-
`[mobx.trace] '${this.name_}' is being read outside a reactive context. Doing a full recompute
|
|
308
|
+
`[mobx.trace] Computed value '${this.name_}' is being read outside a reactive context. Doing a full recompute.`
|
|
292
309
|
)
|
|
293
310
|
}
|
|
294
|
-
if (
|
|
311
|
+
if (
|
|
312
|
+
typeof this.requiresReaction_ === "boolean"
|
|
313
|
+
? this.requiresReaction_
|
|
314
|
+
: globalState.computedRequiresReaction
|
|
315
|
+
) {
|
|
295
316
|
console.warn(
|
|
296
|
-
`[mobx] Computed value ${this.name_} is being read outside a reactive context. Doing a full recompute
|
|
317
|
+
`[mobx] Computed value '${this.name_}' is being read outside a reactive context. Doing a full recompute.`
|
|
297
318
|
)
|
|
298
319
|
}
|
|
299
320
|
}
|
package/src/core/derivation.ts
CHANGED
|
@@ -137,7 +137,10 @@ export function checkIfStateModificationsAreAllowed(atom: IAtom) {
|
|
|
137
137
|
}
|
|
138
138
|
const hasObservers = atom.observers_.size > 0
|
|
139
139
|
// Should not be possible to change observed state outside strict mode, except during initialization, see #563
|
|
140
|
-
if (
|
|
140
|
+
if (
|
|
141
|
+
!globalState.allowStateChanges &&
|
|
142
|
+
(hasObservers || globalState.enforceActions === "always")
|
|
143
|
+
) {
|
|
141
144
|
console.warn(
|
|
142
145
|
"[MobX] " +
|
|
143
146
|
(globalState.enforceActions
|
|
@@ -145,11 +148,14 @@ export function checkIfStateModificationsAreAllowed(atom: IAtom) {
|
|
|
145
148
|
: "Side effects like changing state are not allowed at this point. Are you trying to modify state from, for example, a computed value or the render function of a React component? You can wrap side effects in 'runInAction' (or decorate functions with 'action') if needed. Tried to modify: ") +
|
|
146
149
|
atom.name_
|
|
147
150
|
)
|
|
151
|
+
}
|
|
148
152
|
}
|
|
149
153
|
|
|
150
154
|
export function checkIfStateReadsAreAllowed(observable: IObservable) {
|
|
151
155
|
if (__DEV__ && !globalState.allowStateReads && globalState.observableRequiresReaction) {
|
|
152
|
-
console.warn(
|
|
156
|
+
console.warn(
|
|
157
|
+
`[mobx] Observable '${observable.name_}' being read outside a reactive context.`
|
|
158
|
+
)
|
|
153
159
|
}
|
|
154
160
|
}
|
|
155
161
|
|
|
@@ -189,13 +195,21 @@ export function trackDerivedFunction<T>(derivation: IDerivation, f: () => T, con
|
|
|
189
195
|
}
|
|
190
196
|
|
|
191
197
|
function warnAboutDerivationWithoutDependencies(derivation: IDerivation) {
|
|
192
|
-
if (!__DEV__)
|
|
198
|
+
if (!__DEV__) {
|
|
199
|
+
return
|
|
200
|
+
}
|
|
193
201
|
|
|
194
|
-
if (derivation.observing_.length !== 0)
|
|
202
|
+
if (derivation.observing_.length !== 0) {
|
|
203
|
+
return
|
|
204
|
+
}
|
|
195
205
|
|
|
196
|
-
if (
|
|
206
|
+
if (
|
|
207
|
+
typeof derivation.requiresObservable_ === "boolean"
|
|
208
|
+
? derivation.requiresObservable_
|
|
209
|
+
: globalState.reactionRequiresObservable
|
|
210
|
+
) {
|
|
197
211
|
console.warn(
|
|
198
|
-
`[mobx] Derivation ${derivation.name_} is created/updated without reading any observable value
|
|
212
|
+
`[mobx] Derivation '${derivation.name_}' is created/updated without reading any observable value.`
|
|
199
213
|
)
|
|
200
214
|
}
|
|
201
215
|
}
|
|
@@ -220,14 +234,16 @@ function bindDependencies(derivation: IDerivation) {
|
|
|
220
234
|
const dep = observing[i]
|
|
221
235
|
if (dep.diffValue_ === 0) {
|
|
222
236
|
dep.diffValue_ = 1
|
|
223
|
-
if (i0 !== i)
|
|
237
|
+
if (i0 !== i) {
|
|
238
|
+
observing[i0] = dep
|
|
239
|
+
}
|
|
224
240
|
i0++
|
|
225
241
|
}
|
|
226
242
|
|
|
227
243
|
// Upcast is 'safe' here, because if dep is IObservable, `dependenciesState` will be undefined,
|
|
228
244
|
// not hitting the condition
|
|
229
|
-
if ((
|
|
230
|
-
lowestNewObservingDerivationState = (
|
|
245
|
+
if ((dep as any as IDerivation).dependenciesState_ > lowestNewObservingDerivationState) {
|
|
246
|
+
lowestNewObservingDerivationState = (dep as any as IDerivation).dependenciesState_
|
|
231
247
|
}
|
|
232
248
|
}
|
|
233
249
|
observing.length = i0
|
|
@@ -270,7 +286,9 @@ export function clearObserving(derivation: IDerivation) {
|
|
|
270
286
|
const obs = derivation.observing_
|
|
271
287
|
derivation.observing_ = []
|
|
272
288
|
let i = obs.length
|
|
273
|
-
while (i--)
|
|
289
|
+
while (i--) {
|
|
290
|
+
removeObserver(obs[i], derivation)
|
|
291
|
+
}
|
|
274
292
|
|
|
275
293
|
derivation.dependenciesState_ = IDerivationState_.NOT_TRACKING_
|
|
276
294
|
}
|
|
@@ -309,10 +327,14 @@ export function allowStateReadsEnd(prev: boolean) {
|
|
|
309
327
|
*
|
|
310
328
|
*/
|
|
311
329
|
export function changeDependenciesStateTo0(derivation: IDerivation) {
|
|
312
|
-
if (derivation.dependenciesState_ === IDerivationState_.UP_TO_DATE_)
|
|
330
|
+
if (derivation.dependenciesState_ === IDerivationState_.UP_TO_DATE_) {
|
|
331
|
+
return
|
|
332
|
+
}
|
|
313
333
|
derivation.dependenciesState_ = IDerivationState_.UP_TO_DATE_
|
|
314
334
|
|
|
315
335
|
const obs = derivation.observing_
|
|
316
336
|
let i = obs.length
|
|
317
|
-
while (i--)
|
|
337
|
+
while (i--) {
|
|
338
|
+
obs[i].lowestObserverState_ = IDerivationState_.UP_TO_DATE_
|
|
339
|
+
}
|
|
318
340
|
}
|
package/src/core/globalstate.ts
CHANGED
|
@@ -150,6 +150,11 @@ export class MobXGlobals {
|
|
|
150
150
|
* configurable: true
|
|
151
151
|
*/
|
|
152
152
|
safeDescriptors = true
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Changes with each state update, used by useSyncExternalStore
|
|
156
|
+
*/
|
|
157
|
+
stateVersion = Number.MIN_SAFE_INTEGER
|
|
153
158
|
}
|
|
154
159
|
|
|
155
160
|
let canMergeGlobalState = true
|
|
@@ -157,11 +162,16 @@ let isolateCalled = false
|
|
|
157
162
|
|
|
158
163
|
export let globalState: MobXGlobals = (function () {
|
|
159
164
|
let global = getGlobal()
|
|
160
|
-
if (global.__mobxInstanceCount > 0 && !global.__mobxGlobals)
|
|
161
|
-
|
|
165
|
+
if (global.__mobxInstanceCount > 0 && !global.__mobxGlobals) {
|
|
166
|
+
canMergeGlobalState = false
|
|
167
|
+
}
|
|
168
|
+
if (global.__mobxGlobals && global.__mobxGlobals.version !== new MobXGlobals().version) {
|
|
162
169
|
canMergeGlobalState = false
|
|
170
|
+
}
|
|
163
171
|
|
|
164
172
|
if (!canMergeGlobalState) {
|
|
173
|
+
// Because this is a IIFE we need to let isolateCalled a chance to change
|
|
174
|
+
// so we run it after the event loop completed at least 1 iteration
|
|
165
175
|
setTimeout(() => {
|
|
166
176
|
if (!isolateCalled) {
|
|
167
177
|
die(35)
|
|
@@ -170,7 +180,9 @@ export let globalState: MobXGlobals = (function () {
|
|
|
170
180
|
return new MobXGlobals()
|
|
171
181
|
} else if (global.__mobxGlobals) {
|
|
172
182
|
global.__mobxInstanceCount += 1
|
|
173
|
-
if (!global.__mobxGlobals.UNCHANGED)
|
|
183
|
+
if (!global.__mobxGlobals.UNCHANGED) {
|
|
184
|
+
global.__mobxGlobals.UNCHANGED = {}
|
|
185
|
+
} // make merge backward compatible
|
|
174
186
|
return global.__mobxGlobals
|
|
175
187
|
} else {
|
|
176
188
|
global.__mobxInstanceCount = 1
|
|
@@ -183,12 +195,15 @@ export function isolateGlobalState() {
|
|
|
183
195
|
globalState.pendingReactions.length ||
|
|
184
196
|
globalState.inBatch ||
|
|
185
197
|
globalState.isRunningReactions
|
|
186
|
-
)
|
|
198
|
+
) {
|
|
187
199
|
die(36)
|
|
200
|
+
}
|
|
188
201
|
isolateCalled = true
|
|
189
202
|
if (canMergeGlobalState) {
|
|
190
203
|
let global = getGlobal()
|
|
191
|
-
if (--global.__mobxInstanceCount === 0)
|
|
204
|
+
if (--global.__mobxInstanceCount === 0) {
|
|
205
|
+
global.__mobxGlobals = undefined
|
|
206
|
+
}
|
|
192
207
|
globalState = new MobXGlobals()
|
|
193
208
|
}
|
|
194
209
|
}
|
|
@@ -203,7 +218,10 @@ export function getGlobalState(): any {
|
|
|
203
218
|
*/
|
|
204
219
|
export function resetGlobalState() {
|
|
205
220
|
const defaultGlobals = new MobXGlobals()
|
|
206
|
-
for (let key in defaultGlobals)
|
|
207
|
-
if (persistentKeys.indexOf(key as any) === -1)
|
|
221
|
+
for (let key in defaultGlobals) {
|
|
222
|
+
if (persistentKeys.indexOf(key as any) === -1) {
|
|
223
|
+
globalState[key] = defaultGlobals[key]
|
|
224
|
+
}
|
|
225
|
+
}
|
|
208
226
|
globalState.allowStateChanges = !globalState.enforceActions
|
|
209
227
|
}
|
package/src/core/observable.ts
CHANGED
|
@@ -69,8 +69,9 @@ export function addObserver(observable: IObservable, node: IDerivation) {
|
|
|
69
69
|
// invariantObservers(observable);
|
|
70
70
|
|
|
71
71
|
observable.observers_.add(node)
|
|
72
|
-
if (observable.lowestObserverState_ > node.dependenciesState_)
|
|
72
|
+
if (observable.lowestObserverState_ > node.dependenciesState_) {
|
|
73
73
|
observable.lowestObserverState_ = node.dependenciesState_
|
|
74
|
+
}
|
|
74
75
|
|
|
75
76
|
// invariantObservers(observable);
|
|
76
77
|
// invariant(observable._observers.indexOf(node) !== -1, "INTERNAL ERROR didn't add node");
|
|
@@ -150,7 +151,7 @@ export function reportObserved(observable: IObservable): boolean {
|
|
|
150
151
|
observable.onBO()
|
|
151
152
|
}
|
|
152
153
|
}
|
|
153
|
-
return
|
|
154
|
+
return observable.isBeingObserved_
|
|
154
155
|
} else if (observable.observers_.size === 0 && globalState.inBatch > 0) {
|
|
155
156
|
queueForUnobservation(observable)
|
|
156
157
|
}
|
|
@@ -183,7 +184,9 @@ export function reportObserved(observable: IObservable): boolean {
|
|
|
183
184
|
// Called by Atom when its value changes
|
|
184
185
|
export function propagateChanged(observable: IObservable) {
|
|
185
186
|
// invariantLOS(observable, "changed start");
|
|
186
|
-
if (observable.lowestObserverState_ === IDerivationState_.STALE_)
|
|
187
|
+
if (observable.lowestObserverState_ === IDerivationState_.STALE_) {
|
|
188
|
+
return
|
|
189
|
+
}
|
|
187
190
|
observable.lowestObserverState_ = IDerivationState_.STALE_
|
|
188
191
|
|
|
189
192
|
// Ideally we use for..of here, but the downcompiled version is really slow...
|
|
@@ -202,16 +205,22 @@ export function propagateChanged(observable: IObservable) {
|
|
|
202
205
|
// Called by ComputedValue when it recalculate and its value changed
|
|
203
206
|
export function propagateChangeConfirmed(observable: IObservable) {
|
|
204
207
|
// invariantLOS(observable, "confirmed start");
|
|
205
|
-
if (observable.lowestObserverState_ === IDerivationState_.STALE_)
|
|
208
|
+
if (observable.lowestObserverState_ === IDerivationState_.STALE_) {
|
|
209
|
+
return
|
|
210
|
+
}
|
|
206
211
|
observable.lowestObserverState_ = IDerivationState_.STALE_
|
|
207
212
|
|
|
208
213
|
observable.observers_.forEach(d => {
|
|
209
|
-
if (d.dependenciesState_ === IDerivationState_.POSSIBLY_STALE_)
|
|
214
|
+
if (d.dependenciesState_ === IDerivationState_.POSSIBLY_STALE_) {
|
|
210
215
|
d.dependenciesState_ = IDerivationState_.STALE_
|
|
211
|
-
|
|
216
|
+
if (__DEV__ && d.isTracing_ !== TraceMode.NONE) {
|
|
217
|
+
logTraceInfo(d, observable)
|
|
218
|
+
}
|
|
219
|
+
} else if (
|
|
212
220
|
d.dependenciesState_ === IDerivationState_.UP_TO_DATE_ // this happens during computing of `d`, just keep lowestObserverState up to date.
|
|
213
|
-
)
|
|
221
|
+
) {
|
|
214
222
|
observable.lowestObserverState_ = IDerivationState_.UP_TO_DATE_
|
|
223
|
+
}
|
|
215
224
|
})
|
|
216
225
|
// invariantLOS(observable, "confirmed end");
|
|
217
226
|
}
|
|
@@ -219,15 +228,14 @@ export function propagateChangeConfirmed(observable: IObservable) {
|
|
|
219
228
|
// Used by computed when its dependency changed, but we don't wan't to immediately recompute.
|
|
220
229
|
export function propagateMaybeChanged(observable: IObservable) {
|
|
221
230
|
// invariantLOS(observable, "maybe start");
|
|
222
|
-
if (observable.lowestObserverState_ !== IDerivationState_.UP_TO_DATE_)
|
|
231
|
+
if (observable.lowestObserverState_ !== IDerivationState_.UP_TO_DATE_) {
|
|
232
|
+
return
|
|
233
|
+
}
|
|
223
234
|
observable.lowestObserverState_ = IDerivationState_.POSSIBLY_STALE_
|
|
224
235
|
|
|
225
236
|
observable.observers_.forEach(d => {
|
|
226
237
|
if (d.dependenciesState_ === IDerivationState_.UP_TO_DATE_) {
|
|
227
238
|
d.dependenciesState_ = IDerivationState_.POSSIBLY_STALE_
|
|
228
|
-
if (__DEV__ && d.isTracing_ !== TraceMode.NONE) {
|
|
229
|
-
logTraceInfo(d, observable)
|
|
230
|
-
}
|
|
231
239
|
d.onBecomeStale_()
|
|
232
240
|
}
|
|
233
241
|
})
|
|
@@ -267,6 +275,8 @@ function printDepTree(tree: IDependencyTree, lines: string[], depth: number) {
|
|
|
267
275
|
lines.push("(and many more)")
|
|
268
276
|
return
|
|
269
277
|
}
|
|
270
|
-
lines.push(`${
|
|
271
|
-
if (tree.dependencies)
|
|
278
|
+
lines.push(`${"\t".repeat(depth - 1)}${tree.name}`)
|
|
279
|
+
if (tree.dependencies) {
|
|
280
|
+
tree.dependencies.forEach(child => printDepTree(child, lines, depth + 1))
|
|
281
|
+
}
|
|
272
282
|
}
|
package/src/core/reaction.ts
CHANGED
|
@@ -67,7 +67,7 @@ export class Reaction implements IDerivation, IReactionPublic {
|
|
|
67
67
|
public name_: string = __DEV__ ? "Reaction@" + getNextId() : "Reaction",
|
|
68
68
|
private onInvalidate_: () => void,
|
|
69
69
|
private errorHandler_?: (error: any, derivation: IDerivation) => void,
|
|
70
|
-
public requiresObservable_
|
|
70
|
+
public requiresObservable_?
|
|
71
71
|
) {}
|
|
72
72
|
|
|
73
73
|
onBecomeStale_() {
|
|
@@ -142,7 +142,9 @@ export class Reaction implements IDerivation, IReactionPublic {
|
|
|
142
142
|
// disposed during last run. Clean up everything that was bound after the dispose call.
|
|
143
143
|
clearObserving(this)
|
|
144
144
|
}
|
|
145
|
-
if (isCaughtException(result))
|
|
145
|
+
if (isCaughtException(result)) {
|
|
146
|
+
this.reportExceptionInDerivation_(result.cause)
|
|
147
|
+
}
|
|
146
148
|
if (__DEV__ && notify) {
|
|
147
149
|
spyReportEnd({
|
|
148
150
|
time: Date.now() - startTime
|
|
@@ -157,7 +159,9 @@ export class Reaction implements IDerivation, IReactionPublic {
|
|
|
157
159
|
return
|
|
158
160
|
}
|
|
159
161
|
|
|
160
|
-
if (globalState.disableErrorBoundaries)
|
|
162
|
+
if (globalState.disableErrorBoundaries) {
|
|
163
|
+
throw error
|
|
164
|
+
}
|
|
161
165
|
|
|
162
166
|
const message = __DEV__
|
|
163
167
|
? `[mobx] Encountered an uncaught exception that was thrown by a reaction or observer component, in: '${this}'`
|
|
@@ -165,7 +169,7 @@ export class Reaction implements IDerivation, IReactionPublic {
|
|
|
165
169
|
if (!globalState.suppressReactionErrors) {
|
|
166
170
|
console.error(message, error)
|
|
167
171
|
/** If debugging brought you here, please, read the above message :-). Tnx! */
|
|
168
|
-
} else if (__DEV__) console.warn(`[mobx] (error in reaction '${this.name_}' suppressed, fix error of causing action below)`) // prettier-ignore
|
|
172
|
+
} else if (__DEV__) { console.warn(`[mobx] (error in reaction '${this.name_}' suppressed, fix error of causing action below)`) } // prettier-ignore
|
|
169
173
|
|
|
170
174
|
if (__DEV__ && isSpyEnabled()) {
|
|
171
175
|
spyReport({
|
|
@@ -210,7 +214,9 @@ export function onReactionError(handler: (error: any, derivation: IDerivation) =
|
|
|
210
214
|
globalState.globalReactionErrorHandlers.push(handler)
|
|
211
215
|
return () => {
|
|
212
216
|
const idx = globalState.globalReactionErrorHandlers.indexOf(handler)
|
|
213
|
-
if (idx >= 0)
|
|
217
|
+
if (idx >= 0) {
|
|
218
|
+
globalState.globalReactionErrorHandlers.splice(idx, 1)
|
|
219
|
+
}
|
|
214
220
|
}
|
|
215
221
|
}
|
|
216
222
|
|
|
@@ -225,7 +231,9 @@ let reactionScheduler: (fn: () => void) => void = f => f()
|
|
|
225
231
|
|
|
226
232
|
export function runReactions() {
|
|
227
233
|
// Trampolining, if runReactions are already running, new reactions will be picked up
|
|
228
|
-
if (globalState.inBatch > 0 || globalState.isRunningReactions)
|
|
234
|
+
if (globalState.inBatch > 0 || globalState.isRunningReactions) {
|
|
235
|
+
return
|
|
236
|
+
}
|
|
229
237
|
reactionScheduler(runReactionsHelper)
|
|
230
238
|
}
|
|
231
239
|
|
|
@@ -248,8 +256,9 @@ function runReactionsHelper() {
|
|
|
248
256
|
allReactions.splice(0) // clear reactions
|
|
249
257
|
}
|
|
250
258
|
let remainingReactions = allReactions.splice(0)
|
|
251
|
-
for (let i = 0, l = remainingReactions.length; i < l; i++)
|
|
259
|
+
for (let i = 0, l = remainingReactions.length; i < l; i++) {
|
|
252
260
|
remainingReactions[i].runReaction_()
|
|
261
|
+
}
|
|
253
262
|
}
|
|
254
263
|
globalState.isRunningReactions = false
|
|
255
264
|
}
|
package/src/core/spy.ts
CHANGED
|
@@ -25,14 +25,22 @@ export type PureSpyEvent =
|
|
|
25
25
|
type SpyEvent = PureSpyEvent & { spyReportStart?: true }
|
|
26
26
|
|
|
27
27
|
export function spyReport(event: SpyEvent) {
|
|
28
|
-
if (!__DEV__)
|
|
29
|
-
|
|
28
|
+
if (!__DEV__) {
|
|
29
|
+
return
|
|
30
|
+
} // dead code elimination can do the rest
|
|
31
|
+
if (!globalState.spyListeners.length) {
|
|
32
|
+
return
|
|
33
|
+
}
|
|
30
34
|
const listeners = globalState.spyListeners
|
|
31
|
-
for (let i = 0, l = listeners.length; i < l; i++)
|
|
35
|
+
for (let i = 0, l = listeners.length; i < l; i++) {
|
|
36
|
+
listeners[i](event)
|
|
37
|
+
}
|
|
32
38
|
}
|
|
33
39
|
|
|
34
40
|
export function spyReportStart(event: PureSpyEvent) {
|
|
35
|
-
if (!__DEV__)
|
|
41
|
+
if (!__DEV__) {
|
|
42
|
+
return
|
|
43
|
+
}
|
|
36
44
|
const change = { ...event, spyReportStart: true as const }
|
|
37
45
|
spyReport(change)
|
|
38
46
|
}
|
|
@@ -40,9 +48,14 @@ export function spyReportStart(event: PureSpyEvent) {
|
|
|
40
48
|
const END_EVENT: SpyEvent = { type: "report-end", spyReportEnd: true }
|
|
41
49
|
|
|
42
50
|
export function spyReportEnd(change?: { time?: number }) {
|
|
43
|
-
if (!__DEV__)
|
|
44
|
-
|
|
45
|
-
|
|
51
|
+
if (!__DEV__) {
|
|
52
|
+
return
|
|
53
|
+
}
|
|
54
|
+
if (change) {
|
|
55
|
+
spyReport({ ...change, type: "report-end", spyReportEnd: true })
|
|
56
|
+
} else {
|
|
57
|
+
spyReport(END_EVENT)
|
|
58
|
+
}
|
|
46
59
|
}
|
|
47
60
|
|
|
48
61
|
export function spy(listener: (change: SpyEvent) => void): Lambda {
|
package/src/errors.ts
CHANGED
|
@@ -3,6 +3,17 @@ const niceErrors = {
|
|
|
3
3
|
1(annotationType, key: PropertyKey) {
|
|
4
4
|
return `Cannot apply '${annotationType}' to '${key.toString()}': Field not found.`
|
|
5
5
|
},
|
|
6
|
+
/*
|
|
7
|
+
2(prop) {
|
|
8
|
+
return `invalid decorator for '${prop.toString()}'`
|
|
9
|
+
},
|
|
10
|
+
3(prop) {
|
|
11
|
+
return `Cannot decorate '${prop.toString()}': action can only be used on properties with a function value.`
|
|
12
|
+
},
|
|
13
|
+
4(prop) {
|
|
14
|
+
return `Cannot decorate '${prop.toString()}': computed can only be used on getter properties.`
|
|
15
|
+
},
|
|
16
|
+
*/
|
|
6
17
|
5: "'keys()' can only be used on observable objects, arrays, sets and maps",
|
|
7
18
|
6: "'values()' can only be used on observable objects, arrays, sets and maps",
|
|
8
19
|
7: "'entries()' can only be used on observable objects, arrays and maps",
|
|
@@ -11,9 +22,9 @@ const niceErrors = {
|
|
|
11
22
|
10: "'has()' can only be used on observable objects, arrays and maps",
|
|
12
23
|
11: "'get()' can only be used on observable objects, arrays and maps",
|
|
13
24
|
12: `Invalid annotation`,
|
|
14
|
-
13: `Dynamic observable objects cannot be frozen`,
|
|
25
|
+
13: `Dynamic observable objects cannot be frozen. If you're passing observables to 3rd party component/function that calls Object.freeze, pass copy instead: toJS(observable)`,
|
|
15
26
|
14: "Intercept handlers should return nothing or a change object",
|
|
16
|
-
15: `Observable arrays cannot be frozen`,
|
|
27
|
+
15: `Observable arrays cannot be frozen. If you're passing observables to 3rd party component/function that calls Object.freeze, pass copy instead: toJS(observable)`,
|
|
17
28
|
16: `Modification exception: the internal structure of an observable array was changed.`,
|
|
18
29
|
17(index, length) {
|
|
19
30
|
return `[mobx.array] Index out of bounds, ${index} is larger than ${length}`
|
|
@@ -59,7 +70,9 @@ const niceErrors = {
|
|
|
59
70
|
36: "isolateGlobalState should be called before MobX is running any reactions",
|
|
60
71
|
37(method) {
|
|
61
72
|
return `[mobx] \`observableArray.${method}()\` mutates the array in-place, which is not allowed inside a derivation. Use \`array.slice().${method}()\` instead`
|
|
62
|
-
}
|
|
73
|
+
},
|
|
74
|
+
38: "'ownKeys()' can only be used on observable objects",
|
|
75
|
+
39: "'defineProperty()' can only be used on observable objects"
|
|
63
76
|
} as const
|
|
64
77
|
|
|
65
78
|
const errors: typeof niceErrors = __DEV__ ? niceErrors : ({} as any)
|
package/src/internal.ts
CHANGED
|
@@ -17,6 +17,7 @@ export * from "./types/actionannotation"
|
|
|
17
17
|
export * from "./types/flowannotation"
|
|
18
18
|
export * from "./types/computedannotation"
|
|
19
19
|
export * from "./types/observableannotation"
|
|
20
|
+
export * from "./types/autoannotation"
|
|
20
21
|
export * from "./api/observable"
|
|
21
22
|
export * from "./api/computed"
|
|
22
23
|
export * from "./core/action"
|