Skip to content

Commit dffb006

Browse files
feat(overmind): statemachines blocks asyn mutations
1 parent 038dbd8 commit dffb006

File tree

5 files changed

+69
-9
lines changed

5 files changed

+69
-9
lines changed

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

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
import { PROXY_TREE } from 'proxy-state-tree'
2+
13
import { IAction, createOvermind, createOvermindMock } from './'
24
import { Statemachine, statemachine } from './statemachine'
35

46
describe('Statemachine', () => {
7+
58
test('should set initial state', () => {
69

710
type State = {
@@ -159,4 +162,43 @@ describe('Statemachine', () => {
159162
})
160163
overmind.actions.transition()
161164
})
165+
166+
test('should error when mutating async in transitions', async () => {
167+
expect.assertions(1)
168+
169+
type State = {
170+
machine: Statemachine<'FOO' | 'BAR'>
171+
foo: string
172+
}
173+
174+
const state: State = {
175+
machine: statemachine<'FOO' | 'BAR'>({
176+
initial: 'FOO',
177+
states: {
178+
FOO: ['BAR'],
179+
BAR: ['FOO']
180+
}
181+
}),
182+
foo: 'bar'
183+
}
184+
const transition: Action = ({ state }) => {
185+
return state.machine.BAR(async () => {
186+
await Promise.resolve()
187+
expect(state[PROXY_TREE].master.mutationTree.isBlocking).toBe(true)
188+
})
189+
}
190+
191+
const config = {
192+
state,
193+
actions: {
194+
transition
195+
}
196+
}
197+
198+
interface Action extends IAction<typeof config, void, Promise<void>> {}
199+
200+
const overmind = createOvermind(config)
201+
202+
return overmind.actions.transition()
203+
})
162204
})

packages/node_modules/overmind/src/statemachine.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { VALUE } from 'proxy-state-tree'
1+
import { PROXY_TREE, VALUE } from 'proxy-state-tree'
22

33
import { Derive } from './'
44

@@ -30,7 +30,12 @@ class StateMachine<States extends string> {
3030
if (this[CURRENT_EXIT]) this._currentExit()
3131
this[VALUE][CURRENT_EXIT] = exit
3232
this.current = key as any
33-
return entry && entry()
33+
const tree = (this[PROXY_TREE].master.mutationTree || this[PROXY_TREE])
34+
tree.enableMutations()
35+
const result = entry && entry()
36+
tree.blockMutations()
37+
38+
return result
3439
}
3540
}
3641

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

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1+
import { Proxifier } from './Proxyfier'
12
import {
2-
IProxyStateTree,
3-
IMutationTree,
4-
IMutationCallback,
53
IMutation,
4+
IMutationCallback,
5+
IMutationTree,
66
IProxifier,
7+
IProxyStateTree,
78
} from './types'
8-
import { Proxifier } from './Proxyfier'
99

1010
export class MutationTree<T extends object> implements IMutationTree<T> {
1111
private mutationCallbacks: IMutationCallback[] = []
@@ -15,6 +15,7 @@ export class MutationTree<T extends object> implements IMutationTree<T> {
1515
mutations: IMutation[] = []
1616
objectChanges = new Set<string>()
1717
isTracking: boolean = false
18+
isBlocking: boolean = false
1819
trackPathListeners: Array<(path: string) => void> = []
1920
constructor(master: IProxyStateTree<T>, proxifier?: IProxifier<T>) {
2021
this.isTracking = true
@@ -88,11 +89,17 @@ export class MutationTree<T extends object> implements IMutationTree<T> {
8889
this.mutationCallbacks.push(callback)
8990
}
9091
canMutate() {
91-
return this.isTracking
92+
return this.isTracking && !this.isBlocking
9293
}
9394
canTrack() {
9495
return false
9596
}
97+
blockMutations() {
98+
this.isBlocking = true
99+
}
100+
enableMutations() {
101+
this.isBlocking = false
102+
}
96103
dispose() {
97104
this.isTracking = false
98105
this.mutationCallbacks.length = 0

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ export class Proxifier {
8181
throw new Error(
8282
`proxy-state-tree - You are mutating the path "${path}", but it is not allowed. The following could have happened:
8383
84+
- The mutation is explicitly being blocket
8485
- You are passing state to a 3rd party tool trying to manipulate the state
8586
- You are running asynchronous code and forgot to "await" its execution
8687
`

packages/overmind-website/src/overmind/actions.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
pipe,
99
rehydrate,
1010
} from 'overmind'
11+
import { PROXY_TREE } from 'proxy-state-tree'
1112

1213
import { GuideParams, Page, RouteContext, VideoParams } from './types'
1314

@@ -125,6 +126,10 @@ export const viewHelpGotIt: Action = ({ state }) => {
125126
state.showViewHelp = false
126127
}
127128

128-
export const login: Action = ({ state }) => {
129-
state.mode.authenticating(() => {})
129+
export const login: AsyncAction = ({ state }) => {
130+
return state.mode.authenticating(async () => {
131+
await Promise.resolve()
132+
console.log('UHM?!??', state[PROXY_TREE].isBlocking)
133+
state.query = 'hihihi'
134+
})
130135
}

0 commit comments

Comments
 (0)