Skip to content

Commit 3bbfcb5

Browse files
committed
added support for action short-circuiting
1 parent 78446a5 commit 3bbfcb5

2 files changed

Lines changed: 65 additions & 4 deletions

File tree

src/api/action.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,11 @@ function dontReassignFields() {
6666
invariant(false, process.env.NODE_ENV !== "production" && "@action fields are not reassignable")
6767
}
6868

69-
const boundActionDecorator = function(target, propertyName, descriptor) {
70-
debugger
69+
const boundActionDecorator = function(target, propertyName, descriptor, applyToInstance?: boolean) {
70+
if (applyToInstance === true) {
71+
defineBoundAction(this, propertyName, descriptor.value)
72+
return null
73+
}
7174
if (descriptor) {
7275
if (descriptor.value)
7376
// Typescript / Babel: @action.bound method() { }
@@ -104,14 +107,23 @@ const boundActionDecorator = function(target, propertyName, descriptor) {
104107
}
105108

106109
export var action: IActionFactory = function action(arg1, arg2?, arg3?, arg4?): any {
107-
debugger
108110
if (arguments.length === 1 && typeof arg1 === "function")
109111
return createAction(arg1.name || "<unnamed action>", arg1)
110112
if (arguments.length === 2 && typeof arg2 === "function") return createAction(arg1, arg2)
111113

112114
if (arguments.length === 1 && typeof arg1 === "string") return namedActionDecorator(arg1)
113115

114-
return namedActionDecorator(arg2).apply(null, arguments)
116+
if (arg4 === true) {
117+
// apply to instance immediately
118+
return {
119+
value: createAction(name, arg3.value),
120+
enumerable: false,
121+
configurable: false,
122+
writable: false
123+
}
124+
} else {
125+
return namedActionDecorator(arg2).apply(null, arguments)
126+
}
115127
} as any
116128

117129
action.bound = boundActionDecorator as any

test/base/action.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,55 @@ test("computed values and actions", () => {
372372
expect(calls).toBe(3)
373373
})
374374

375+
test("extendObservable respects action decorators", () => {
376+
debugger
377+
const x = mobx.observable.object(
378+
// TODO remove .object
379+
{
380+
a1() {
381+
return this
382+
},
383+
a2() {
384+
return this
385+
},
386+
a3() {
387+
return this
388+
}
389+
},
390+
{
391+
a1: mobx.action,
392+
a2: mobx.action.bound
393+
}
394+
)
395+
expect(mobx.isAction(x.a1)).toBe(true)
396+
expect(mobx.isAction(x.a2)).toBe(true)
397+
expect(mobx.isAction(x.a3)).toBe(false)
398+
399+
const global = (function() {
400+
return this
401+
})()
402+
403+
const { a1, a2, a3 } = x
404+
expect(a1.call(x)).toBe(x)
405+
// expect(a1()).toBe(global)
406+
expect(a2.call(x)).toBe(x)
407+
expect(a2()).toBe(x)
408+
expect(a3.call(x)).toBe(x)
409+
// expect(a3()).toBe(global)
410+
})
411+
412+
test("expect warning for invalid decorator", () => {
413+
expect(() => {
414+
mobx.observable({ x: 1 }, { x: undefined })
415+
}).toThrow(/Not a valid decorator for 'x', got: undefined/)
416+
})
417+
418+
test("expect warning superfluos decorator", () => {
419+
expect(() => {
420+
mobx.observable({ x() {} }, { y: mobx.action })
421+
}).toThrow(/Not a valid decorator for 'x', got: undefined/)
422+
})
423+
375424
// TODO re-enable
376425
test.skip("bound actions bind", () => {
377426
var called = 0

0 commit comments

Comments
 (0)