Search code examples
reactjsreduxredux-saga

Redux saga dispatching actions from inside map inside saga-action


I have API calls in the following manner:

  1. Call main api which gives me an array of objects.
  2. For each object inside array I have to call another API asynchronously.
  3. As soon as the sub API call for the object is finished, update its data in redux store which is an array (ofc) and show it.

So the scenario is a list showing items which grow in dynamic fashion.

Since I am using redux-saga, I have to dispatch the second part from inside an redux-action. I have tried the follow way:

const response = yield call(get, 'endpoint')

const configHome = response.map(function* (ele) {
    const data = yield call(get, ele.SomeURI + '?someParameter=' + ele.someObject.id)
}))

This doesn't work since map doesn't know anything about generator functions. So I tried this:

const response = yield call(get, 'endpoint')

const configHome = yield all(response.map((ele) => {

     return call(get, paramsBuilder(undefined, ele.CategoryID))

}))

But this will block my UI from showing available data untill all sub API calls are finished.

I have also tried making a separate generator function which I call from inside map and call its .next() function but the problem here again is that saga doesn't control that generator function so the call effect doesn't return any value properly.

Completely stuck on this part. Would appreciate any help.


Solution

  • Have you tried this, I have created a sample this might help

    import { put, takeLatest, all, call } from 'redux-saga/effects';
    function* _fetchNews(id) {
      const data = yield fetch(
        `https://jsonplaceholder.typicode.com/todos/${id}`
      ).then(function(response) {
        const data = response.json();
        return data;
      });
      console.log(id);
      yield put({ type: 'NEWS_RECEIVED', data });
      return data;
    }
    
    function* _getData() {
      const json = yield fetch('https://jsonplaceholder.typicode.com/todos').then(
        response => response.json()
      );
      return json;
    }
    
    function* fetchNews() {
      const json = yield _getData();
      const configHome = json.map(ele => _fetchNews(ele.id));
      for (var item of configHome) {
        yield item;
      }
    }
    
    function* actionWatcher() {
      yield takeLatest('GET_NEWS', fetchNews);
    }
    
    export default function* rootSaga() {
      yield all([actionWatcher()]);
    }