Skip to content

Commit 54e3f71

Browse files
authored
fix: Fix Set interceptors (#4528)
* fix(observableset): use the new value returned from the interceptor * test(set): add a couple of interceptor tests * chore(changeset): add patch entry --------- Co-authored-by: k-g-a <[email protected]>
1 parent 3cb7539 commit 54e3f71

File tree

3 files changed

+69
-14
lines changed

3 files changed

+69
-14
lines changed

.changeset/set-interceptors.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"mobx": patch
3+
---
4+
5+
Fix observable.set not respecting the new value from interceptors

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

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,3 +474,48 @@ describe("Observable Set methods are reactive", () => {
474474
expect(c).toBe(3)
475475
})
476476
})
477+
478+
479+
describe("Observable Set interceptors", () => {
480+
481+
let s = set()
482+
483+
beforeEach(() => {
484+
s = set()
485+
})
486+
487+
test("Add does not add value if interceptor returned no change", () => {
488+
mobx.intercept(s, (change) => {
489+
if(change.type === 'add' && change.newValue === 2) {
490+
return undefined;
491+
}
492+
493+
return change;
494+
})
495+
496+
s.add(1);
497+
s.add(2);
498+
499+
expect([...s]).toStrictEqual([1]);
500+
501+
502+
})
503+
504+
test("Add respects newValue from interceptor", () => {
505+
506+
mobx.intercept(s, (change) => {
507+
if(change.type === 'add' && change.newValue === 2) {
508+
change.newValue = 10;
509+
}
510+
511+
return change;
512+
})
513+
514+
s.add(1);
515+
s.add(2);
516+
517+
expect([...s]).toStrictEqual([1, 10])
518+
})
519+
520+
521+
})

packages/mobx/src/types/observableset.ts

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -51,17 +51,20 @@ export type ISetDidChange<T = any> =
5151
oldValue: T
5252
}
5353

54+
export type ISetWillDeleteChange<T = any> = {
55+
type: "delete"
56+
object: ObservableSet<T>
57+
oldValue: T
58+
};
59+
export type ISetWillAddChange<T = any> = {
60+
type: "add"
61+
object: ObservableSet<T>
62+
newValue: T
63+
};
64+
5465
export type ISetWillChange<T = any> =
55-
| {
56-
type: "delete"
57-
object: ObservableSet<T>
58-
oldValue: T
59-
}
60-
| {
61-
type: "add"
62-
object: ObservableSet<T>
63-
newValue: T
64-
}
66+
| ISetWillDeleteChange<T>
67+
| ISetWillAddChange<T>
6568

6669
export class ObservableSet<T = any> implements Set<T>, IInterceptable<ISetWillChange>, IListenable {
6770
[$mobx] = ObservableSetMarker
@@ -120,16 +123,18 @@ export class ObservableSet<T = any> implements Set<T>, IInterceptable<ISetWillCh
120123
add(value: T) {
121124
checkIfStateModificationsAreAllowed(this.atom_)
122125
if (hasInterceptors(this)) {
123-
const change = interceptChange<ISetWillChange<T>>(this, {
126+
const change = interceptChange<ISetWillAddChange<T>>(this, {
124127
type: ADD,
125128
object: this,
126129
newValue: value
127130
})
128131
if (!change) {
129132
return this
130133
}
131-
// ideally, value = change.value would be done here, so that values can be
132-
// changed by interceptor. Same applies for other Set and Map api's.
134+
135+
// implemented reassignment same as it's done for ObservableMap
136+
value = change.newValue!;
137+
133138
}
134139
if (!this.has(value)) {
135140
transaction(() => {
@@ -164,7 +169,7 @@ export class ObservableSet<T = any> implements Set<T>, IInterceptable<ISetWillCh
164169

165170
delete(value: T) {
166171
if (hasInterceptors(this)) {
167-
const change = interceptChange<ISetWillChange<T>>(this, {
172+
const change = interceptChange<ISetWillDeleteChange<T>>(this, {
168173
type: DELETE,
169174
object: this,
170175
oldValue: value

0 commit comments

Comments
 (0)