Skip to content

Commit 3336da0

Browse files
fix(overmind): allow class instances to add derived
1 parent f80e493 commit 3336da0

File tree

6 files changed

+61
-29
lines changed

6 files changed

+61
-29
lines changed

packages/node_modules/overmind/src/derived.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,4 +338,23 @@ describe('Derived', () => {
338338

339339
expect(runCount).toBe(2)
340340
})
341+
test('should be able to add derived to class instances', () => {
342+
class SomeClass {
343+
foo = derived((state: SomeClass) => state.bar + '!')
344+
bar = 'foo'
345+
}
346+
type State = {
347+
class: SomeClass
348+
}
349+
const state: State = {
350+
class: new SomeClass()
351+
}
352+
const config = {
353+
state,
354+
}
355+
356+
const app = new Overmind(config)
357+
358+
expect(app.state.class.foo).toEqual('foo!')
359+
})
341360
})

packages/node_modules/overmind/src/index.ts

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import {
4848
import {
4949
EXECUTION,
5050
IS_OPERATOR,
51+
IS_PROXY_BOUND_FUNCTION,
5152
IS_TEST,
5253
MODE_DEFAULT,
5354
MODE_SSR,
@@ -72,7 +73,7 @@ export { SERIALIZE, rehydrate } from './rehydrate'
7273

7374
export { Statemachine, statemachine } from './statemachine'
7475

75-
export const derived = <S extends IState, R extends IState, O>(cb: (state: S, rootState: R) => O): O => {
76+
export const derived = <S extends object, R extends object, O>(cb: (state: S, rootState: R) => O): O => {
7677
cb[IS_DERIVED_CONSTRUCTOR] = true
7778
return cb as any
7879
}
@@ -393,24 +394,37 @@ export class Overmind<ThisConfig extends IConfiguration>
393394
{
394395
devmode,
395396
delimiter: this.delimiter,
396-
onFunction: (tree, path, func) => {
397+
onSetFunction: (proxy, tree, path, target, prop, func) => {
398+
if (func[IS_DERIVED_CONSTRUCTOR]) {
399+
return new Derived(func) as any
400+
}
401+
402+
func = func.bind(proxy)
403+
func[IS_PROXY_BOUND_FUNCTION] = true
404+
return func
405+
},
406+
onGetFunction: (proxy, tree, path, target, prop) => {
407+
let func = target[prop]
408+
397409
if (func[IS_DERIVED]) {
398-
return { func, value: func(eventHub, tree, proxyStateTree, path.split(this.delimiter)) }
410+
return func(eventHub, tree, proxyStateTree, path.split(this.delimiter))
399411
}
400412

401413
if (func[IS_DERIVED_CONSTRUCTOR]) {
402414
const derived = new Derived(func) as any
415+
target[prop] = derived
403416

404-
return {
405-
func: derived,
406-
value: derived(eventHub, tree, proxyStateTree, path.split(this.delimiter))
407-
}
417+
return derived(eventHub, tree, proxyStateTree, path.split(this.delimiter))
408418
}
409419

410-
return {
411-
func,
412-
value: func
420+
if (func[IS_PROXY_BOUND_FUNCTION]) {
421+
return func
413422
}
423+
424+
func = func.bind(proxy)
425+
func[IS_PROXY_BOUND_FUNCTION] = true
426+
target[prop] = func
427+
return func
414428
},
415429
onGetter: devmode
416430
? (path, value) => {

packages/node_modules/overmind/src/utils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export const IS_TEST = process.env.NODE_ENV === 'test'
55
export const IS_OPERATOR = Symbol('operator')
66
export const ORIGINAL_ACTIONS = Symbol('origina_actions')
77
export const EXECUTION = Symbol('execution')
8+
export const IS_PROXY_BOUND_FUNCTION = Symbol('is_proxy_bound_function')
89

910
export const MODE_DEFAULT = Symbol('MODE_DEFAULT')
1011
export const MODE_TEST = Symbol('MODE_TEST')

packages/node_modules/proxy-state-tree/src/Proxyfier.ts

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -258,21 +258,17 @@ export class Proxifier {
258258
const nestedPath = proxifier.concat(path, prop)
259259
const currentTree = trackingTree || proxifier.tree
260260

261-
if (typeof targetValue === 'function' && isClass(target)) {
262-
return (...args) => targetValue.call(proxy, ...args)
263-
} else if (typeof targetValue === 'function') {
264-
if (proxifier.tree.master.options.onFunction) {
265-
const { func, value } = proxifier.tree.master.options.onFunction(
261+
if (typeof targetValue === 'function') {
262+
if (proxifier.tree.master.options.onGetFunction) {
263+
return proxifier.tree.master.options.onGetFunction(
264+
proxy,
266265
trackingTree || proxifier.tree,
267266
nestedPath,
268-
targetValue
267+
target,
268+
prop
269269
)
270-
271-
target[prop] = func
272-
273-
return value
274270
}
275-
return targetValue.call(target, proxifier.tree, nestedPath)
271+
return isClass(target) ? (...args) => targetValue.call(proxy, ...args) : targetValue.call(target, proxifier.tree, nestedPath)
276272
} else {
277273
currentTree.trackPathListeners.forEach((cb) => cb(nestedPath))
278274
trackingTree && trackingTree.proxifier.trackPath(nestedPath)
@@ -301,17 +297,18 @@ export class Proxifier {
301297
const mutationTree = proxifier.getMutationTree()
302298
const existingValue = target[prop]
303299

304-
if (typeof value === 'function' && proxifier.tree.master.options.onFunction) {
305-
const result = proxifier.tree.master.options.onFunction(
300+
if (typeof value === 'function' && proxifier.tree.master.options.onSetFunction) {
301+
value = proxifier.tree.master.options.onSetFunction(
302+
proxy,
306303
proxifier.getTrackingTree() || proxifier.tree,
307304
nestedPath,
305+
target,
306+
prop,
308307
value
309308
)
310-
311-
value = result.func
312309
}
313310

314-
const hasChangedValue = value !== target[prop]
311+
const hasChangedValue = existingValue !== value
315312
const result = Reflect.set(target, prop, value)
316313

317314
mutationTree.addMutation(

packages/node_modules/proxy-state-tree/src/index.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -755,8 +755,8 @@ describe('FUNCTIONS', () => {
755755
},
756756
}
757757
const tree = new ProxyStateTree(state, {
758-
onFunction: (proxyStateTree, path, func) =>
759-
({ func, value: func('foo', proxyStateTree, path)}),
758+
onGetFunction: (proxy, proxyStateTree, path, target, prop) =>
759+
target[prop]('foo', proxyStateTree, path),
760760
})
761761

762762
const accessTree = tree.getTrackStateTree().track(() => {})

packages/node_modules/proxy-state-tree/src/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ export interface ITrackStateTree<T extends object> {
7373
export interface IOptions {
7474
delimiter?: string
7575
devmode?: boolean
76-
onFunction?: (...args: any[]) => { func: Function, value: any }
76+
onSetFunction?: (...args: any[]) => any
77+
onGetFunction?: (...args: any[]) => any
7778
onGetter?: Function
7879
}
7980

0 commit comments

Comments
 (0)