Skip to content

Commit fab2557

Browse files
feat(overmind): statemachines now has explicit effects and state callback
1 parent 7dcf140 commit fab2557

File tree

2 files changed

+60
-7
lines changed

2 files changed

+60
-7
lines changed

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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,4 +456,42 @@ describe('Statemachine', () => {
456456

457457
expect(() => overmind.actions.transition()).not.toThrow()
458458
})
459+
test('should deal with transition effects', async () => {
460+
type States = {
461+
current: 'FOO'
462+
} | {
463+
current: 'BAR',
464+
number: number
465+
}
466+
467+
const state = statemachine<States>({
468+
FOO: ['BAR'],
469+
BAR: ['FOO']
470+
}, {
471+
current: 'FOO',
472+
})
473+
const transition: Action = ({ state }) => {
474+
return state.transition('BAR', { number: 123 }, () => {
475+
return Promise.resolve(4321)
476+
}, (barState, value) => {
477+
barState.number = value
478+
})
479+
}
480+
481+
const config = {
482+
state,
483+
actions: {
484+
transition
485+
}
486+
}
487+
488+
interface Action extends IAction<typeof config, void, Promise<void>> {}
489+
490+
const overmind = createOvermindMock(config)
491+
// @ts-ignore
492+
overmind.isStrict = true
493+
494+
await overmind.actions.transition()
495+
expect(overmind.state.current === 'BAR' && overmind.state.number === 4321).toBe(true)
496+
})
459497
})

packages/node_modules/overmind/src/statemachine.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,18 @@ export interface MachineMethods<States extends TStates, Base extends IState = {}
3434
matches<T extends States["current"], O = void>(state: T | T[], cb: (current: Statemachine<Base, States, States extends {
3535
current: T
3636
} ? States : never>) => O): O;
37-
transition<T extends States["current"], O = void>(
37+
transition<T extends States["current"], O = void, O2 = O>(
3838
state: T,
3939
newState: States extends {
4040
current: T
4141
} ? Exact<Omit<States, 'current'>, {}> extends never ? Omit<States, 'current'> & Partial<Base> : Exact<Partial<Base>, {}> extends never ? Partial<Base> : { [NO_PROP]?: true} : never,
42-
callback?: ((current: Statemachine<Base, States, States extends {
42+
effectsCallback?: ((current: Statemachine<Base, States, States extends {
4343
current: T
44-
} ? States : never>) => O)
45-
): O;
44+
} ? States : never>) => O),
45+
stateCallback?: ((current: Statemachine<Base, States, States extends {
46+
current: T
47+
} ? States : never>, value: O extends Promise<infer V> ? V : O) => O2)
48+
): O extends Promise<any> ? Promise<O2> : O2;
4649
}
4750

4851
export type Statemachine<Base extends IState, States extends TStates, State extends TStates = States> = Base extends never ? State & MachineMethods<States> : Base & State & MachineMethods<States, Base>
@@ -86,7 +89,7 @@ export class StateMachine<Base extends IState, States extends TStates, State ext
8689
return result
8790
}
8891
}
89-
transition(state, newState, callback) {
92+
transition(state, newState, effectsCallback, stateCallback) {
9093
const transitions = this[VALUE][TRANSITIONS]
9194

9295
if (transitions[this.current].includes(state)) {
@@ -108,8 +111,20 @@ export class StateMachine<Base extends IState, States extends TStates, State ext
108111
tree.blockMutations()
109112

110113
let result
111-
if (callback) {
112-
result = callback(this)
114+
if (effectsCallback) {
115+
result = effectsCallback(this)
116+
}
117+
118+
if (stateCallback && result instanceof Promise) {
119+
return result.then((value) => {
120+
if (this.current !== state) {
121+
return value
122+
}
123+
tree.enableMutations()
124+
const result = stateCallback(this, value)
125+
tree.blockMutations()
126+
return result
127+
})
113128
}
114129

115130
return result

0 commit comments

Comments
 (0)