Basic Redux Saga

ref – https://medium.com/@ravindermahajan/why-use-redux-saga-f3413a3f7e34
https://redux-saga.js.org/docs/introduction/BeginnerTutorial/
https://redux-saga.js.org/docs/advanced/RacingEffects/
https://redux-saga.js.org/docs/advanced/RunningTasksInParallel/

source download

Reducers.js

First, we have reducers, which takes in actions, evaluate its type and return an updated state.
Reducers are executed whenever an action object is returned, or store.dispatch({…}) is executed

Component

Next we create an component. The component takes in four props. The current store value, an increment function, a decrement button, and async increment button. The component’s JSX has three buttons, each of which onclick will execute a passed in prop. Then it simply displays the store’s value.

Then let’s create a component Counter

Main

Now let’s first look at Main’s render function. It renders our Counter component with passed in values for props. Specifically, it passes in its store state for prop value.
On increment, it passes in an anonymous function that calls store.dispatch, which executes an action object with action type of INCREMENT or DECREMENT.

So our action types match up with what we have in reducer.

Adding in Redux Saga

Redux saga acts as a middleware that gives developers the scope to neatly separate any business logic, Ajax requests, data manipulation or any other operation which may not seem appropriate in reducers directly.

Original Working without redux saga:-
Action(s) → Reducer(s)
With Redux saga as middleware:-
Action(s) → Redux Saga →Reducer(s)

Benefits of using Saga:

  • Great support for Async Operations
  • It takes care of basic needs like cancelling previous saga operation on start of new eg: cancel previous xhr call on typeahead search query.
  • Can resolve a race between different effects (https://redux-saga.js.org/docs/advanced/RacingEffects/)
  • Running tasks in parallel like Promise.all (https://redux-saga.js.org/docs/advanced/RunningTasksInParallel/)
  • …and many other features

Let’s plug Saga into our simple application.
First, let’s create a Saga file.

Sagas are implemented as Generator functions that yield objects to the redux-saga middleware.

Saga

We implement a Promise that takes ms seconds to resolve. Once the Promise is resolved, the middleware will resume the Saga, executing code until the next yield.

We implement simple generator function that logs

We then create rootSaga function and yield all. This will execute all our saga functions when saga is run in main.js

In our example, we want to run helloSaga function that simply logs, and also execute a listener. This listener listens for action type INCREMENT_ASYNC.

Let’s implement this watchIncrementAsync

We use takeEvery, a helper function provided by redux-saga, to listen for store.dispatch({INCREMENT_ASYNC}) and run incrementAsync each time.

As you can see, it’s a listener that listens for INCREMENT_ASYNC. Once INCREMENT_ASYNC is dispatched by store.dispatch, then we execute incrementAsync.

Let’s implement incrementAsync

As mentioned previously, middleware will suspend the Saga until the Promise completes.
put is one example of what we call an Effect.
Effects are plain JavaScript objects which contain instructions to be fulfilled by the middleware.
put instructs the middleware to dispatch an action to the Store.

When a middleware retrieves an Effect yielded by a Saga, the Saga is paused until the Effect is fulfilled.

The action INCREMENT will reach reducer, where reducer will return state + 1.

Since the store is subscribed to the render, once the state changes, it will redraw and we’ll get an updated value.