An alternate method of orchestrating complex or async actions in redux. A method where side effects are described instead of executed w/in your source.
long‑lived db trans. CQRS ‑ coordinates and routes messages between contexts Distributed systems ‑ manage long‑running business process "Process manager"
function that returns a generator object when called Starts "paused" Generator object's n e x t method resumes execution Contains y i e l d keyword Function body execution pauses on y i e l d y i e l d defines return value
n * i d M a k e r ( ) { l e t i n d e x = 0 w h i l e ( i n d e x < 3 ) y i e l d i n d e x + + } v a r g e n = i d M a k e r ( ) c o n s o l e . l o g ( g e n . n e x t ( ) . v a l u e ) / / 0 c o n s o l e . l o g ( g e n . n e x t ( ) . v a l u e ) / / 1 c o n s o l e . l o g ( g e n . n e x t ( ) . v a l u e ) / / 2 c o n s o l e . l o g ( g e n . n e x t ( ) . v a l u e ) / / u n d e f i n e d
d u x ‐ s a g a / I O " : t r u e , " C A L L " : { " c o n t e x t " : n u l l , " a r g s " : [ " / a p i / m a s t e r m i n d / 7 7 6 d e 5 5 2 . . . / g u e s s " , { " d a t a " : { " g u e s s " : [ " r e d " , " r e d " , " y e l l o w " , " y e l l o w " ] } } ] } }
e d u x ‐ s a g a / I O " : t r u e , " P U T " : { " c h a n n e l " : n u l l , " a c t i o n " : { " t y p e " : " g u e s s / C R E A T E _ S U C C E S S " , " g u e s s " : [ " r e d " , " r e d " , " y e l l o w " , " y e l l o w " ] , " f e e d b a c k " : { " k e y s " : { " b l a c k s " : 1 , " w h i t e s " : 0 } } , " a l e r t s " : [ ] } } }
{ c a l l , p u t } f r o m ' r e d u x ‐ s a g a / e f f e c t s ' i m p o r t t e s t f r o m ' a v a ' i m p o r t * a s a c t i o n s f r o m ' . . / a c t i o n s ' i m p o r t * a s a p i f r o m ' . . / a p i ' i m p o r t * a s s u b j e c t f r o m ' . . / s a g a s ' c o n s t { d e s e r i a l i z e E r r o r , d e s . . } = a p i . c r e a t e t e s t ( ' # c r e a t e h a n d l e s a r e q u e s t s u c c e s s ' , t = > { c o n s t r e s = { s t a t u s : 2 0 0 , d a t a : { d a t a : { s o m e : ' r e s p o n s e ' } } } c o n s t g e n = s u b j e c t . c r e a t e ( ) t . d e e p E q u a l ( g e n . n e x t ( ) . v a l u e , c a l l ( r e q u e s t , f o r m a t U r l ( ) ) ) t . d e e p E q u a l ( g e n . n e x t ( r e s ) . v a l u e , p u t ( a c t i o n s . c r e a t e S u c c e s s ( d e s e r i a l i z e S u c c e s s ( r e s ) ) ) ) t . t r u t h y ( g e n . n e x t ( ) . d o n e ) } )
# c r e a t e h a n d l e s a r e q u e s t e r r o r ' , t = > { c o n s t r e s = { s t a t u s : 5 0 0 , d a t a : { e r r o r s : [ { s o m e : ' e r r o r ' } ] } } c o n s t g e n = s u b j e c t . c r e a t e ( ) t . d e e p E q u a l ( g e n . n e x t ( ) . v a l u e , c a l l ( r e q u e s t , f o r m a t U r l ( ) ) ) t . d e e p E q u a l ( g e n . t h r o w ( r e s ) . v a l u e , p u t ( a c t i o n s . c r e a t e E r r o r ( d e s e r i a l i z e E r r o r ( r e s ) ) ) ) t . t r u t h y ( g e n . n e x t ( ) . d o n e ) } )
c a l l , p u t } f r o m ' r e d u x ‐ s a g a / e f f e c t s ' i m p o r t * a s a c t i o n s f r o m ' . / a c t i o n s ' i m p o r t * a s a p i f r o m ' . / a p i ' e x p o r t f u n c t i o n * c r e a t e ( ) { c o n s t { d e s e r i a l i z e E r r o r , d e s . . . } = a p i . c r e a t e t r y { c o n s t r e s = y i e l d c a l l ( r e q u e s t , f o r m a t U r l ( ) ) y i e l d p u t ( a c t i o n s . c r e a t e S u c c e s s ( d e s e r i a l i z e S u c c e s s ( r e s ) ) ) } c a t c h ( r e s ) { i f ( r e s i n s t a n c e o f E r r o r ) t h r o w r e s y i e l d p u t ( a c t i o n s . c r e a t e E r r o r ( d e s e r i a l i z e E r r o r ( r e s ) ) ) } }
t { a p p l y M i d d l e w a r e , c o m b i n e R e d u c e r s , c r e a t e S t o r e } f r o m ' r e d u x ' i m p o r t c r e a t e S a g a M i d d l e w a r e f r o m ' r e d u x ‐ s a g a ' i m p o r t * a s r e d u c e r s f r o m ' . / r e d u c e r s ' i m p o r t s a g a s f r o m ' . / s a g a s ' c o n s t s a g a M i d d l e w a r e = c r e a t e S a g a M i d d l e w a r e ( ) / / ! c o n s t c r e a t e S t o r e W i t h M i d d l e w a r e = a p p l y M i d d l e w a r e ( s a g a M i d d l e w a r e / / ! ) ( c r e a t e S t o r e ) c o n s t r o o t R e d u c e r = c o m b i n e R e d u c e r s ( r e d u c e r s ) c o n s t s t o r e = c r e a t e S t o r e W i t h M i d d l e w a r e ( r o o t R e d u c e r ) s a g a M i d d l e w a r e . r u n ( s a g a s ) / / !
r t { t a k e E v e r y } f r o m ' r e d u x ‐ s a g a ' i m p o r t { f o r k } f r o m ' r e d u x ‐ s a g a / e f f e c t s ' i m p o r t * a s g a m e A c t i o n s f r o m ' . . / . . / g a m e / a c t i o n s ' i m p o r t * a s g a m e S a g a s f r o m ' . . / . . / g a m e / s a g a s ' e x p o r t d e f a u l t f u n c t i o n * r o o t ( ) { y i e l d * [ f o r k ( t a k e E v e r y , g a m e A c t i o n s . T Y P E S . C R E A T E , g a m e S a g a s . c r e a t e ) , . . . ] }
t y p e s f r o m ' r e d u x ‐ t y p e s ' e x p o r t c o n s t T Y P E S = t y p e s ( ' g a m e ' , ' C R E A T E ' , ' C R E A T E _ S U C C E S S ' , ' C R E A T E _ E R R O R ' ) e x p o r t f u n c t i o n c r e a t e ( ) { r e t u r n { t y p e : T Y P E S . C R E A T E } } e x p o r t f u n c t i o n c r e a t e S u c c e s s ( g a m e ) { r e t u r n { t y p e : T Y P E S . C R E A T E _ S U C C E S S , g a m e } } e x p o r t f u n c t i o n c r e a t e E r r o r ( e r r o r s ) { r e t u r n { t y p e : T Y P E S . C R E A T E _ E R R O R , e r r o r s } }
{ P r o v i d e r } f r o m ' r e a c t ‐ r e d u x ' i m p o r t R e a c t f r o m ' r e a c t ' i m p o r t { r e n d e r } f r o m ' r e a c t ‐ d o m ' i m p o r t G a m e f r o m ' . / g a m e ' i m p o r t * a s g a m e A c t i o n s f r o m ' . / g a m e / a c t i o n s ' i m p o r t s t o r e f r o m ' . / c o m m o n / s t o r e ' s t o r e . d i s p a t c h ( g a m e A c t i o n s . c r e a t e ( ) ) / / ! r e n d e r ( < P r o v i d e r s t o r e = { s t o r e } > < G a m e / > < / P r o v i d e r > , d o c u m e n t . g e t E l e m e n t B y I d ( ' a p p ' ) )
r t { T Y P E S } f r o m ' . . / g a m e / a c t i o n s ' e x p o r t c o n s t i n i t i a l S t a t e = { i d : n u l l } f u n c t i o n c r e a t e S u c c e s s ( s t a t e , a c t i o n ) { r e t u r n { . . . s t a t e , i d : a c t i o n . g a m e . i d } } e x p o r t d e f a u l t f u n c t i o n r e d u c e ( s t a t e = i n i t i a l S t a t e , a c t i o n = { } c o n s t h a n d l e r s = { [ T Y P E S . C R E A T E _ S U C C E S S ] : c r e a t e S u c c e s s } r e t u r n h a n d l e r s [ a c t i o n . t y p e ] ? h a n d l e r s [ a c t i o n . t y p e ] ( s t a t e , a c t i o n ) : s t a t e }
a c t i o n N a m e ( [ . . . a r g s ] ) { r e t u r n f u n c t i o n t h e T h u n k ( d i s p a t c h , g e t S t a t e ) { s t a t e m e n t s } }
ects access to state & dispatch ditto, via e ff ect helpers dispatch multiple times ditto, via e ff ect helpers invoked later, in middleware* later, in middleware test stub promises assert e ff ects *except for in tests
t * a s a p i f r o m ' . / a p i ' e x p o r t f u n c t i o n c r e a t e ( ) { r e t u r n a s y n c d i s p a t c h = > { c o n s t { d e s e r i a l i z e E r r o r , d e s . . . } = a p i . c r e a t e t r y { c o n s t r e s = a w a i t r e q u e s t ( f o r m a t U r l ( ) ) d i s p a t c h ( c r e a t e S u c c e s s ( d e s e r i a l i z e S u c c e s s ( r e s ) ) ) } c a t c h ( r e s ) { i f ( r e s i n s t a n c e o f E r r o r ) t h r o w r e s d i s p a t c h ( c r e a t e E r r o r ( d e s e r i a l i z e E r r o r ( r e s ) ) ) } } }
t t d f r o m ' t e s t d o u b l e ' / / ! i m p o r t t e s t f r o m ' a v a ' i m p o r t * a s a p i f r o m ' . . / a p i ' i m p o r t * a s s u b j e c t f r o m ' . . / a c t i o n s ' t e s t ( ' # c r e a t e r e q u e s t s g a m e a n d h a n d l e s s u c c e s s ' , t = > { c o n s t d i s p a t c h = t d . f u n c t i o n ( ' d i s p a t c h ' ) / / ! c o n s t g a m e = { s o m e : ' g a m e ' } c o n s t r e s = { d a t a : { d a t a : [ g a m e ] } } / / ! c o n s t r e q P r o m i s e = n e w P r o m i s e ( r e s o l v e = > r e s o l v e ( r e s ) ) / / ! t d . r e p l a c e ( a p i . c r e a t e , ' r e q u e s t ' , ( ) = > r e q P r o m i s e ) / / ! s u b j e c t . c r e a t e ( ) ( d i s p a t c h ) r e t u r n r e q P r o m i s e . t h e n ( _ = > { / / ! t d . v e r i f y ( d i s p a t c h ( s u b j e c t . c r e a t e S u c c e s s ( g a m e ) ) ) } ) } )
' # c r e a t e r e q u e s t s g a m e a n d h a n d l e s e r r o r ' , t = > { c o n s t d i s p a t c h = t d . f u n c t i o n ( ' d i s p a t c h ' ) c o n s t e r r o r s = [ { s o m e : ' e r r o r s ' } ] c o n s t s t a t u s = 4 0 0 c o n s t r e s = { s t a t u s , d a t a : { e r r o r s } } c o n s t r e q P r o m i s e = n e w P r o m i s e ( ( _ , r e j e c t ) = > r e j e c t ( r e s ) ) t d . r e p l a c e ( a p i . c r e a t e , ' r e q u e s t ' , ( ) = > r e q P r o m i s e ) s u b j e c t . c r e a t e ( ) ( d i s p a t c h ) r e t u r n r e q P r o m i s e . c a t c h ( _ = > { t d . v e r i f y ( d i s p a t c h ( s u b j e c t . c r e a t e E r r o r ( [ { . . . e r r o r s [ 0 ] , s t a t u s } ] ) ) ) } ) } )
maintenance pain Less inclined to focus on action module ‑ "the stub game" Implicit testing/coupling to other modules has crept in Setting up fake Promises Async in test flow