Skip to content

Commit 1138e57

Browse files
feat(overmind-react): support strict and concurrent mode, so far
1 parent 9320491 commit 1138e57

File tree

1 file changed

+50
-34
lines changed
  • packages/node_modules/overmind-react/src

1 file changed

+50
-34
lines changed

packages/node_modules/overmind-react/src/index.ts

Lines changed: 50 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import 'proxy-state-tree'
2-
2+
import { unstable_scheduleCallback, unstable_getCurrentPriorityLevel, unstable_cancelCallback } from 'scheduler'
33
import {
44
EventType,
55
IConfiguration,
@@ -53,26 +53,20 @@ export const Provider: React.ProviderExoticComponent<
5353
React.ProviderProps<Overmind<IConfiguration> | OvermindMock<IConfiguration>>
5454
> = context.Provider
5555

56-
const useForceRerender = () => {
57-
const [flushId, setState] = react.useState(() => -1)
58-
// We use memo here, instead of ref, to support fast-refresh
59-
const mountedRef = react.useMemo(() => ({ current: true}), [])
56+
function useForceRerender() {
57+
const [{ flushId }, setTick] = react.useState({ tick: 0, flushId: 0})
6058

61-
react.useEffect(
62-
() => () => {
63-
mountedRef.current = false
64-
},
65-
[]
66-
)
59+
const forceRerender = react.useCallback((flushId?) => {
60+
setTick(current => ({
61+
...current,
62+
tick: current.tick + 1,
63+
flushId: flushId || current.flushId
64+
}))
65+
}, [])
6766

68-
const forceRerender = (_, __, flushId): void => {
69-
if (mountedRef.current) {
70-
setState(flushId)
71-
}
72-
}
7367
return {
74-
forceRerender,
75-
flushId,
68+
flushId,
69+
forceRerender
7670
}
7771
}
7872

@@ -99,23 +93,31 @@ const useState = <Config extends IConfiguration>(): Overmind<Config>['state'] =
9993
return overmind.state
10094
}
10195

102-
const tree = react.useMemo<any>(() =>
103-
(overmind as any).proxyStateTree.getTrackStateTree(), []
104-
)
96+
const trackingRef = react.useRef<any>(null)
10597

106-
if (IS_PRODUCTION) {
107-
const { forceRerender } = useForceRerender()
98+
const {flushId, forceRerender} = useForceRerender()
99+
100+
if (!trackingRef.current) {
101+
trackingRef.current = {
102+
tree: (overmind as any).proxyStateTree.getTrackStateTree(),
103+
hasUpdatedBeforeCommit: false,
104+
stopTrackingTask: unstable_scheduleCallback(unstable_getCurrentPriorityLevel(), () => {
105+
trackingRef.current.tree.stopTracking()
106+
})
107+
}
108+
}
108109

110+
if (IS_PRODUCTION) {
109111
react.useEffect(
110112
() => () => {
111-
;(overmind as any).proxyStateTree.disposeTree(tree)
113+
;(overmind as any).proxyStateTree.disposeTree(trackingRef.current.tree)
112114
},
113115
[]
114116
)
115117

116-
react.useLayoutEffect(() => tree.stopTracking())
118+
react.useLayoutEffect(() => trackingRef.current.tree.stopTracking())
117119

118-
tree.track(forceRerender)
120+
trackingRef.current.tree.track(forceRerender)
119121
} else {
120122
const component = useCurrentComponent()
121123
const name = component.name
@@ -128,18 +130,21 @@ const useState = <Config extends IConfiguration>(): Overmind<Config>['state'] =
128130
currentComponentInstanceId++
129131
)
130132

131-
const { flushId, forceRerender } = useForceRerender()
132-
133133
react.useLayoutEffect(() => {
134+
trackingRef.current.mounted = true
134135
overmind.eventHub.emitAsync(EventType.COMPONENT_ADD, {
135136
componentId: component.__componentId,
136137
componentInstanceId,
137138
name,
138-
paths: Array.from(tree.pathDependencies) as any,
139+
paths: Array.from(trackingRef.current.tree.pathDependencies) as any,
139140
})
140141

142+
if (trackingRef.current.hasUpdatedBeforeCommit) {
143+
forceRerender()
144+
}
145+
141146
return () => {
142-
;(overmind as any).proxyStateTree.disposeTree(tree)
147+
;(overmind as any).proxyStateTree.disposeTree(trackingRef.current.tree)
143148
overmind.eventHub.emitAsync(EventType.COMPONENT_REMOVE, {
144149
componentId: component.__componentId,
145150
componentInstanceId,
@@ -149,19 +154,30 @@ const useState = <Config extends IConfiguration>(): Overmind<Config>['state'] =
149154
}, [])
150155

151156
react.useLayoutEffect(() => {
152-
tree.stopTracking()
157+
if (trackingRef.current.stopTrackingTask) {
158+
unstable_cancelCallback(trackingRef.current.stopTrackingTask)
159+
trackingRef.current.stopTrackingTask = null
160+
}
161+
trackingRef.current.tree.stopTracking()
153162
overmind.eventHub.emitAsync(EventType.COMPONENT_UPDATE, {
154163
componentId: component.__componentId,
155164
componentInstanceId,
156165
name,
157166
flushId,
158-
paths: Array.from(tree.pathDependencies) as any,
167+
paths: Array.from(trackingRef.current.tree.pathDependencies) as any,
159168
})
160169
})
161-
tree.track(forceRerender)
170+
trackingRef.current.tree.track(() => {
171+
if (trackingRef.current.mounted) {
172+
forceRerender()
173+
} else {
174+
trackingRef.current.hasUpdatedBeforeCommit = true
175+
}
176+
})
162177
}
178+
163179

164-
return tree.state
180+
return trackingRef.current.tree.state
165181
}
166182

167183
const useActions = <Config extends IConfiguration>(): Overmind<Config>['actions'] => {

0 commit comments

Comments
 (0)