Skip to content

Commit c8d9374

Browse files
authored
Fix #3747: computed values can get stale if backing observable was created and updated outside tracking context (#3748)
1 parent 4ffc001 commit c8d9374

File tree

3 files changed

+25
-11
lines changed

3 files changed

+25
-11
lines changed

.changeset/witty-falcons-explode.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"mobx": patch
3+
---
4+
5+
Fixed: #3747, computed values becoming stale if the underlying observable was created and updated outside a reactive context

packages/mobx/__tests__/v5/base/observables.js

+11
Original file line numberDiff line numberDiff line change
@@ -2382,6 +2382,7 @@ test("state version updates correctly", () => {
23822382
o.x++
23832383
})
23842384

2385+
// expect(o.x).toBe(4) is 1?
23852386
prevStateVersion = getGlobalState().stateVersion
23862387
o.x++
23872388
expect(o.x).toBe(5)
@@ -2505,3 +2506,13 @@ test("state version does not update on observable creation", () => {
25052506
check(() => mobx.observable([0], { proxy: true }))
25062507
check(() => mobx.computed(() => 0))
25072508
})
2509+
2510+
test("#3747", () => {
2511+
mobx.runInAction(() => {
2512+
const o = observable.box(0)
2513+
const c = computed(() => o.get())
2514+
expect(c.get()).toBe(0)
2515+
o.set(1)
2516+
expect(c.get()).toBe(1) // would fail
2517+
})
2518+
})

packages/mobx/src/core/atom.ts

+9-11
Original file line numberDiff line numberDiff line change
@@ -68,21 +68,19 @@ export class Atom implements IAtom {
6868
* Invoke this method _after_ this method has changed to signal mobx that all its observers should invalidate.
6969
*/
7070
public reportChanged() {
71-
if (globalState.inBatch && this.batchId_ === globalState.batchId) {
72-
// Called from the same batch this atom was created in.
73-
return
71+
if (!globalState.inBatch || this.batchId_ !== globalState.batchId) {
72+
// We could update state version only at the end of batch,
73+
// but we would still have to switch some global flag here to signal a change.
74+
globalState.stateVersion =
75+
globalState.stateVersion < Number.MAX_SAFE_INTEGER
76+
? globalState.stateVersion + 1
77+
: Number.MIN_SAFE_INTEGER
78+
// Avoids the possibility of hitting the same globalState.batchId when it cycled through all integers (necessary?)
79+
this.batchId_ = NaN
7480
}
75-
// Avoids the possibility of hitting the same globalState.batchId when it cycled through all integers (necessary?)
76-
this.batchId_ = NaN
7781

7882
startBatch()
7983
propagateChanged(this)
80-
// We could update state version only at the end of batch,
81-
// but we would still have to switch some global flag here to signal a change.
82-
globalState.stateVersion =
83-
globalState.stateVersion < Number.MAX_SAFE_INTEGER
84-
? globalState.stateVersion + 1
85-
: Number.MIN_SAFE_INTEGER
8684
endBatch()
8785
}
8886

0 commit comments

Comments
 (0)