import React , { useReducer , useRef , useMemo , useEffect , useContext , Reducer , ReducerState , ReducerAction , Dispatch , createContext } from 'react' ; import { runSaga , stdChannel , Saga , RunSagaOptions , SagaMonitor , EffectMiddleware } from 'redux-saga' ; type SagaIOKeys = keyof Pick < RunSagaOptions < any , any > , 'channel' | 'dispatch' | 'getState' > ; type ExposedRunSagaOptions < A , S > = Omit < RunSagaOptions < A , S > , SagaIOKeys > ; interface SagaProdiderProps extends ExposedRunSagaOptions < any , any > { } const SagaContext = createContext < SagaProdiderProps > ( { } ) ; param props export const SagaProvider = ( { children , ... props } ) => { return < SagaContext . Provider value = { props } children = { children } / > ; } ; type VoidMethod = ( ... args : any [ ] ) => void ; function mergeVoidMethods ( contextMethod , localMethod ) { if ( ! contextMethod && ! localMethod ) { return ; } if ( contextMethod && ! localMethod ) { return contextMethod ; } if ( ! contextMethod && localMethod ) { return localMethod ; } return ( ... args ) => { contextMethod ! ( ... args ) ; localMethod ! ( ... args ) ; } ; } function mergeSagaMonitors ( contextMonitor , localMonitor ) { if ( ! contextMonitor && ! localMonitor ) { return ; } if ( contextMonitor && ! localMonitor ) { return contextMonitor ; } if ( ! contextMonitor && localMonitor ) { return localMonitor ; } const sagaMonitorKeys = [ 'actionDispatched' , 'effectCancelled' , 'effectRejected' , 'effectResolved' , 'effectTriggered' , 'rootSagaStarted' ] ; const combinedSagaMonitor = { } ; for ( const key of sagaMonitorKeys ) { const method = mergeVoidMethods ( contextMonitor ! [ key ] , localMonitor ! [ key ] ) ; if ( method ) { combinedSagaMonitor [ key ] = method ; } } return combinedSagaMonitor ; } function mergeEffectMiddlewares ( contextMiddlewares , localMiddlewares ) { if ( ! contextMiddlewares && ! localMiddlewares ) { return ; } if ( contextMiddlewares && ! localMiddlewares ) { return contextMiddlewares ; } if ( ! contextMiddlewares && localMiddlewares ) { return localMiddlewares ; } return [ ... contextMiddlewares ! , ... localMiddlewares ! ] ; } see https example export function useSagaReducer < S extends Saga < never [ ] > , R extends Reducer < any , any > , I > ( /**
 * Saga method, called when the component mounts, must be a generator function.
 * Same as would be passed to reduxSaga.runSaga
 */ saga , /**
 * Reducer method, passed into React's `useReducer` method
 */ reducer , /**
 * Optional initalized argument, passed into React's `useReducer` method
 */ initializerArg ? , /**
 * Store initialized function, passed into React's `useReducer` method
 */ initializer ? , see https runSagaOptions ? ) { const [ state , reactDispatch ] = useReducer ( reducer , initializerArg as any , initializer as any ) ; const stateRef = useRef ( state ) ; useEffect ( ( ) => { stateRef . current = state ; } , [ state ] ) ; const sagaIO = useMemo ( ( ) => { const channel = stdChannel ( ) ; const dispatch = ( action ) => { reactDispatch ( action ) ; Promise . resolve ( ) . then ( ( ) => { channel . put ( action ) ; } ) ; } ; const getState = ( ) => stateRef . current ; return { channel , dispatch , getState } ; } , [ ] ) ; const sagaContext = useContext ( SagaContext ) ; useEffect ( ( ) => { const options = runSagaOptions || { } ; const context = { ... sagaContext . context , ... options . context } ; const sagaMonitor = mergeSagaMonitors ( sagaContext . sagaMonitor , options . sagaMonitor ) ; const onError = mergeVoidMethods ( sagaContext . onError , options . onError ) ; const effectMiddlewares = mergeEffectMiddlewares ( sagaContext . effectMiddlewares , options . effectMiddlewares ) ; const sagaOptions = { ... sagaIO , context , sagaMonitor , onError , effectMiddlewares } ; const task = runSaga < any , any , any > ( sagaOptions , saga ) ; return ( ) => { task . cancel ( ) ; } ; } , [ ] ) ; return [ state , sagaIO . dispatch ] ; } param type param payload export function makeCustomEffect ( type , payload ) { return { '@@redux-saga/custom' : true , combinator : false , type , payload } ; } export default useSagaReducer ;