Redux saga 从 saga-action 内部的 map 调度动作

Redux saga dispatching actions from inside map inside saga-action

我有 API 调用方式如下:

  1. 调用 main api 这会给我一个对象数组。
  2. 对于数组中的每个对象,我必须异步调用另一个 API。
  3. 一旦对对象的子 API 调用完成,就在 redux 存储中更新它的数据,它是一个数组 (ofc) 并显示它。

所以场景是一个列表,显示以动态方式增长的项目。

因为我使用的是 redux-saga,所以我必须从 redux-action 中发送第二部分。我尝试了以下方式:

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

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

这不起作用,因为 map 对生成器函数一无所知。所以我尝试了这个:

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

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

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

}))

但这会阻止我的 UI 显示可用数据,直到所有子 API 调用完成。

我也尝试制作一个单独的生成器函数,我从 map 内部调用它并调用它的 .next() 函数,但这里的问题又是 saga 不控制那个生成器函数,所以调用效果不return 任何值都正确。

完全卡在这部分。非常感谢任何帮助。

你试过了吗,我已经创建了一个示例,这可能 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()]);
}

yield all - 生成器会被阻塞,直到所有效果都被解决或者一个被拒绝

所以你需要为每个子单独发送事件API

假设您有 2 个操作:

export const getMainApi =() => ({
  type: types.GET_MAIN_API,
});

export const getSubApi = endpoint => ({
  type: types.GET_SUB_API,
  endpoint,
});

那么您的操作将是:

const get = endpoint => fetch(endpoint).then(response => response);

function* fetchMainApi(action) {
  try {
    const response = yield call(get, 'endpoint');
    for (let i = 0; i < response.length; i += 1) {
      // dispatch here all sub APIs
      yield put(
        getSubApi(
          response[i].SomeURI + '?someParameter=' + response[i].someObject.id,
        ),
      );
    }
  } catch (e) {
    console.log(e);
  }
}

function* fetchSubApi(action) {
  try {
    const response = yield call(get, action.endpoint);
    yield put({
      type: types.RECEIVE_SUB_API,
      response
    });
  } catch (e) {
    console.log(e);
  }
}

takeLatest(type.GET_MAIN_API, fetchMainApi)
takeEvery(types.GET_SUB_API, fetchSubApi)

因此,在成功接收子 APIs 后,您需要将数据插入 reducer 中的状态。

这只是伪代码。