A common abstraction: Effect
To generalize: waiting for a future action, waiting for the future result of a function call like
yield delay(1000)
, or waiting for the result of a dispatch all are the same concept. In all cases,
we are yielding some form of Effects.
What a Saga does is actually compose all those effects together to implement the desired control flow.
The simplest is to sequence yielded Effects by just putting the yields one after another. You can also use the
familiar control flow operators (if
, while
, for
) to implement more sophisticated control flows. Or you
you can use the provided Effects combinators to express concurrency (yield race) and parallelism (yield [...]).
You can even yield calls to other Sagas, allowing the powerful routine/subroutine pattern.
For example, incrementAsync
uses an infinite loop while(true)
which means it will stay alive
for the entirety of the application's lifetime.
You can also create Sagas that last a limited amount of time. For example, the following Saga
waits for the first 3 INCREMENT_COUNTER
actions, triggers a showCongratulation()
action and then finishes.
function* onBoarding() {
for(let i = 0; i < 3; i++)
yield take(INCREMENT_COUNTER)
yield put( showCongratulation() )
}