@@ -132,12 +132,67 @@ module MakeReducer = (DeferredAction: HasDeferredAction) => {
132132 // This way, we hide implementation (unsafe) tricks.
133133 (userState , send , defer )
134134 }
135- }
136135
137- // TODO: Implement this for Restate
138- // ReactUpdate.useReducerWithMapState (reducer<'state, 'action>, () => 'state) => ('state, dispatch<'action>)
139- // React.useReducerWithMapState(
140- // ('state, 'action) => 'state,
141- // 'initialState,
142- // 'initialState => 'state,
143- // ) => ('state, 'action => unit)
136+ let useReducerWithMapState = (
137+ reducer : reducer <'state , 'action >, // The reducer provided by the user
138+ scheduler : scheduler <'state , 'action >, // The scheduler provided by the user
139+ createInitialState : () => 'state , // A function to map the initial state
140+ ) => {
141+ let cleanupFnsRef : React .ref <Belt .Map .String .t <option <unit => unit >>> = React .useRef (Belt .Map .String .empty )
142+ let ({userState , deferredActionsQueue }, internalDispatch ) = React .useReducerWithMapState (
143+ ({userState , deferredActionsQueue } as internalState , internalAction ) =>
144+ switch internalAction {
145+ | WiredAction (action ) =>
146+ switch reducer (userState , action ) {
147+ | NoUpdate => internalState
148+ | Update (state ) => {... internalState , userState : state }
149+ | UpdateWithDeferred (state , deferredAction ) => {
150+ userState : state ,
151+ deferredActionsQueue : Belt .List .concat (deferredActionsQueue , list {deferredAction }),
152+ }
153+ | Deferred (deferredAction ) => {
154+ ... internalState ,
155+ deferredActionsQueue : Belt .List .concat (deferredActionsQueue , list {deferredAction }),
156+ }
157+ }
158+ | PushDeferred (deferredAction ) => {
159+ ... internalState ,
160+ deferredActionsQueue : Belt .List .concat (deferredActionsQueue , list {deferredAction }),
161+ }
162+ | PopDeferred (tailDeferredActions ) => {
163+ ... internalState ,
164+ deferredActionsQueue : tailDeferredActions ,
165+ }
166+ }
167+ , (), initialState => {userState : createInitialState (initialState ), deferredActionsQueue : list {}}
168+ )
169+ let defer : schedule = deferredAction => internalDispatch (PushDeferred (deferredAction ))
170+ let send : dispatch <'action > = action => internalDispatch (WiredAction (action ))
171+ React .useEffect1 (() => {
172+ switch (deferredActionsQueue ) {
173+ | list {deferredAction , ... queueTail } =>
174+ cleanupFnsRef .current
175+ -> Belt .Map .String .get (DeferredAction .variantId (deferredAction ))
176+ -> Belt .Option .map (mPrevCleanupFn => mPrevCleanupFn -> Belt .Option .map (prevCleanupFn => prevCleanupFn ()))
177+ -> ignore
178+ let mNewCleanupFn = scheduler ({state : userState , send , defer }, deferredAction )
179+ cleanupFnsRef .current = cleanupFnsRef .current -> Belt .Map .String .set (DeferredAction .variantId (deferredAction ), mNewCleanupFn )
180+ internalDispatch (PopDeferred (queueTail ))
181+ | list {} => ()
182+ }
183+ None
184+ }, [deferredActionsQueue ])
185+ React .useEffect0 (() => {
186+ Some (() => {
187+ cleanupFnsRef .current
188+ -> Belt .Map .String .valuesToArray
189+ -> Belt .Array .forEach (
190+ mCleanupFn => mCleanupFn -> Belt .Option .forEach (cleanupFn => cleanupFn ())
191+ )
192+ }
193+ )
194+ }
195+ )
196+ (userState , send , defer )
197+ }
198+ }
0 commit comments