$30 off During Our Annual Pro Sale. View Details »

Handling Async Actions with Redux Saga

Handling Async Actions with Redux Saga

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.

Jake Trent

July 14, 2016
Tweet

More Decks by Jake Trent

Other Decks in Programming

Transcript

  1. Handling Async Actions with
    Redux Saga
    Jake Trent

    View Slide

  2. What is this talk about?
    Assumes working knowledge of redux
    Fundamentals of redux‑saga
    redux‑saga in practice

    View Slide

  3. What is redux?
    "Predictable state container"
    Flux variant
    Single state tree
    Pure function state reducers
    Popular ecosystem

    View Slide

  4. What is a saga?
    1987 Garcia‑Molina and Salem paper ‑ long‑lived db trans.
    CQRS ‑ coordinates and routes messages between contexts
    Distributed systems ‑ manage long‑running business process
    "Process manager"

    View Slide

  5. What is redux‑saga?
    JS lib
    "Alternate side e

    ect model for redux apps"
    Responsible for "orchestrating complex/asynchronous ops"

    View Slide

  6. What makes it work?
    Sagas are generator functions ‑‑ feel like action creators
    Sagas return e

    ects ‑‑ descriptors of instructions to exec later
    E

    ects captured and executed in saga redux middleware

    View Slide

  7. What is a generator?
    Way to handle async code
    JS 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

    View Slide

  8. Generator syntax
    f
    u
    n
    c
    t
    i
    o
    n
    * n
    a
    m
    e
    (
    [
    p
    a
    r
    a
    m
    [
    , p
    a
    r
    a
    m
    [
    , .
    .
    . p
    a
    r
    a
    m
    ]
    ]
    ]
    ) {
    s
    t
    a
    t
    e
    m
    e
    n
    t
    s
    }

    View Slide

  9. Simple generator example
    f
    u
    n
    c
    t
    i
    o
    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

    View Slide

  10. What does a generator object return?
    {
    v
    a
    l
    u
    e
    : 1
    ,
    d
    o
    n
    e
    : f
    a
    l
    s
    e
    }

    View Slide

  11. Where can I use generators?
    Native in Node since v0.12
    Browser via babel‑polyfill
    Other languages have this feature
    eg, C# "iterator methods"

    View Slide

  12. What is an e

    ect?
    JS object
    Descriptor of instructions
    Instructions to be executed later

    View Slide

  13. What are e

    ect helpers?
    redux‑saga ‑provided functions
    Format e

    ects for saga middleware

    View Slide

  14. Some e

    ect helpers
    c
    a
    l
    l ‑ for calling async
    p
    u
    t ‑ for dispatching actions
    s
    e
    l
    e
    c
    t ‑ for querying state

    View Slide

  15. E

    ect shape
    {
    "
    @
    @
    r
    e
    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
    "
    ]
    }
    }
    ]
    }
    }

    View Slide

  16. Another e

    ect example
    {
    "
    @
    @
    r
    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
    "
    : [
    ]
    }
    }
    }

    View Slide

  17. How do I use redux‑saga in a project?
    Test and write sagas
    Attach sagas to redux store
    Associate an action to each saga
    Call actions as normal
    Dispatch actions to reducers as normal

    View Slide

  18. Mastermind demo game

    View Slide

  19. Test a saga (1/2)
    i
    m
    p
    o
    r
    t { 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
    )
    }
    )

    View Slide

  20. Test a saga (2/2)
    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 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
    )
    }
    )

    View Slide

  21. Write a saga
    i
    m
    p
    o
    r
    t { 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
    )
    )
    )
    }
    }

    View Slide

  22. Attach saga to redux store
    i
    m
    p
    o
    r
    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
    ) /
    / !

    View Slide

  23. Associate an action to each saga
    i
    m
    p
    o
    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
    )
    ,
    .
    .
    .
    ]
    }

    View Slide

  24. Write actions as normal
    i
    m
    p
    o
    r
    t 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 }
    }

    View Slide

  25. Call actions as normal
    i
    m
    p
    o
    r
    t { 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
    '
    )
    )

    View Slide

  26. Dispatch actions to reducers as normal
    i
    m
    p
    o
    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
    }

    View Slide

  27. Compared to redux‑thunk?

    View Slide

  28. redux‑thunk syntax
    f
    u
    n
    c
    t
    i
    o
    n 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
    }
    }

    View Slide

  29. redux‑thunk's idea
    Similarly, execute action later
    When has access to store's dispatch function and state

    View Slide

  30. Compared to redux‑thunk?
    thunk saga
    action returns function e

    ects
    access to state & dispatch ditto, via e

    ect helpers
    dispatch multiple times ditto, via e

    ect helpers
    invoked later, in middleware* later, in middleware
    test stub promises assert e

    ects
    *except for in tests

    View Slide

  31. Action using redux‑thunk and Promises
    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
    (
    ) {
    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
    )
    )
    )
    }
    }
    }

    View Slide

  32. Action test using Promises (1/2)
    i
    m
    p
    o
    r
    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
    )
    )
    )
    }
    )
    }
    )

    View Slide

  33. Action test using Promises (2/2)
    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 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 }
    ]
    )
    )
    )
    }
    )
    }
    )

    View Slide

  34. Testing Promises feels worse
    More stubs required ‑ setup and 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

    View Slide

  35. Review: re‑create a saga for mastermind

    View Slide

  36. I like redux‑saga
    Complex/async action flows
    More pleasant testing experience
    Feels like more like a pure function
    Generators are less familiar than functions
    Fun to try a new method of organization

    View Slide

  37. Thank you!
    jaketrent.com
    @jaketrent
    mastermind‑saga.herokuapp.com

    View Slide