11import 'proxy-state-tree'
2-
2+ import { unstable_scheduleCallback , unstable_getCurrentPriorityLevel , unstable_cancelCallback } from 'scheduler'
33import {
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
167183const useActions = < Config extends IConfiguration > ( ) : Overmind < Config > [ 'actions' ] => {
0 commit comments