Skip to content

Commit b05c2df

Browse files
committed
Make sure action.bound uses the proxy as this if available
1 parent a27b849 commit b05c2df

2 files changed

Lines changed: 66 additions & 31 deletions

File tree

src/api/actiondecorator.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import {
44
addHiddenProp,
55
createAction,
66
defineBoundAction,
7-
fail
7+
fail,
8+
$mobx
89
} from "../internal"
10+
import { isObservableObject } from "../types/observableobject"
911

1012
function dontReassignFields() {
1113
fail(process.env.NODE_ENV !== "production" && "@action fields are not reassignable")
@@ -62,10 +64,6 @@ export function actionFieldDecorator(name: string) {
6264
}
6365

6466
export function boundActionDecorator(target, propertyName, descriptor, applyToInstance?: boolean) {
65-
if (applyToInstance === true) {
66-
defineBoundAction(target, propertyName, descriptor.value)
67-
return null
68-
}
6967
if (descriptor) {
7068
// if (descriptor.value)
7169
// Typescript / Babel: @action.bound method() { }
@@ -74,10 +72,11 @@ export function boundActionDecorator(target, propertyName, descriptor, applyToIn
7472
configurable: true,
7573
enumerable: false,
7674
get() {
75+
const self = isObservableObject(this) ? this[$mobx].proxy || this : this
7776
defineBoundAction(
78-
this,
77+
self,
7978
propertyName,
80-
descriptor.value || descriptor.initializer.call(this)
79+
descriptor.value || descriptor.initializer.call(self)
8180
)
8281
return this[propertyName]
8382
},

test/base/proxies.js

Lines changed: 60 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
computed,
23
decorate,
34
isComputedProp,
45
isAction,
@@ -182,30 +183,6 @@ test("for-in operator", () => {
182183
expect(computeKeys(x)).toEqual(["z", "a"])
183184
})
184185

185-
test("bound actions", () => {
186-
const x = observable(
187-
{
188-
a1() {
189-
return this
190-
}
191-
},
192-
{
193-
a1: action.bound
194-
}
195-
)
196-
197-
extendObservable(x, {
198-
a2() {
199-
return this
200-
}
201-
})
202-
203-
// x is the proxy, so it cannot be this if this was bound during creation...
204-
expect(x.a1()).not.toBe(x)
205-
// x was bound later, so it's will work fine
206-
expect(x.a2()).toBe(x)
207-
})
208-
209186
test("type coercion doesn't break", () => {
210187
const x = observable({})
211188
expect("" + x).toBe("[object Object]")
@@ -335,3 +312,62 @@ test("decorate proxies", () => {
335312
expect(stripAdminFromDescriptors(Object.getOwnPropertyDescriptors(a))).toMatchSnapshot()
336313
expect(Object.keys(a)).toEqual(["x", "b"])
337314
})
315+
316+
test("predictable 'this' - 1", () => {
317+
debugger
318+
const a = observable.object(
319+
{
320+
a0() {
321+
return this
322+
},
323+
a1() {
324+
return this
325+
},
326+
a2() {
327+
return this
328+
},
329+
get computed() {
330+
return this
331+
}
332+
},
333+
{
334+
a1: action,
335+
a2: action.bound
336+
}
337+
)
338+
339+
expect(a.a0()).toBe(a)
340+
expect(a.a1()).toBe(a)
341+
expect(a.a2()).toBe(a) // pre-bound!
342+
// expect(a.computed).toBe(a)
343+
})
344+
345+
test("predictable 'this' - 2", () => {
346+
class A {
347+
a0() {
348+
return this
349+
}
350+
351+
@action
352+
a1() {
353+
return this
354+
}
355+
356+
@action.bound
357+
a2() {
358+
return this
359+
}
360+
361+
@computed
362+
get computed() {
363+
return this
364+
}
365+
}
366+
367+
const a = new A()
368+
369+
expect(a.a0()).toBe(a)
370+
expect(a.a1()).toBe(a)
371+
expect(a.a2()).toBe(a)
372+
expect(a.computed).toBe(a)
373+
})

0 commit comments

Comments
 (0)