Redux-Saga: What/Why/How + examples
Tags: redux, beginners, javascript, react
Published: 2020-06-01 09:47:16

#What

[Redux-Saga](https://redux-saga.js.org/) is here for you to help with side effects in your app, especially if those side effects are impacting your global state - **Redux** store. It is a **redux-middleware**, which handle async tasks with javascript **generators**.

#Why

You can think of **Redux-Saga** as of separate thread, where in synchronous way a very complex asynchronous scenarios can be described. Thanks to this it is much easier for developer to read, understand and maintain complex async business logic. In my experience, I have learnt that **Redux-Saga** is more developer friendly (after you will learn it basis) comparing to [Redux Middleware](https://redux.js.org/advanced/middleware) or [Redux Thunk](https://github.com/reduxjs/redux-thunk)

#How

In `main.js` file plug **Root Saga** from `saga.js` to the store using `applyMiddleware` function.

`main.js`

```javascript
import { createStore, applyMiddleware } from 'redux'
import createSagaMiddleware from 'redux-saga'

import reducer from './reducers'
import rootSaga from './sagas'

// create the saga middleware
const sagaMiddleware = createSagaMiddleware()
// mount it on the Store
const store = createStore(
  reducer,
  applyMiddleware(sagaMiddleware)
)

// then run the saga
sagaMiddleware.run(rootSaga)
```

Your **Root Saga** just combine all other sagas (generators).

`sagas.js`

```javascript
export default function* rootSaga() {
  yield all([
    firstSaga(),
    ...
    actionWatcher(),
    ...
    lastSaga()
  ])
}
```

#Examples

Fetch data

```javascript
export function* fetchData(action) {
   try {
      // make API call using `Api.fetchUser` function (could be fetch) for 
      // url stored in variable `action.payload.url`
      const data = yield call(Api.fetchUser, action.payload.url)
      // send `FETCH_SUCCEEDED` action with payload `data`, it will reach 
      // all reducers and sagas that are 'listening' to it
      yield put({type: "FETCH_SUCCEEDED", data})
   } catch (error) {
      // send `FETCH_FAILED` action to inform about error with API call
      yield put({type: "FETCH_FAILED", error})
   }
}
```

Execute logic after multiple actions

```javascript
function* businessFlow() {
  while (true) {
    // wait for the ACTION_1
    yield take('ACTION_1')
    // ... perform the logic
    // wait for the ACTION_2
    yield take('ACTION_2')
    // ... perform some other logic
  }
}
```

Race

```javascript
function* someTask() {
  while (true) { ... }
}

function* watchTask() {
    // `someTask` will be cancelled when CANCEL_TASK will be caught by the 
    // Saga
    yield race({
      task: call(someTask),
      cancel: take('CANCEL_TASK')
    })
}
```

Cancel previous call

If multiple `GET_DATA` actions will be fired, only the last one will be processed (all previous calls of `fetchData` will be cancelled)

```javascript
function* fetchData() {
  try {
      const data = yield call(Api.fetchUser, action.payload.url)
      yield put({type: "FETCH_SUCCEEDED", data})
   } catch (error) {
      yield put({type: "FETCH_FAILED", error})
   }
}
function* actionWatcher() {
     yield takeLatest('GET_DATA', fetchData)
}
```

This was only short highlight of the **Redux-Saga**, for more check the [docs](https://redux-saga.js.org/)