Redux saga 从 saga-action 内部的 map 调度动作
Redux saga dispatching actions from inside map inside saga-action
我有 API 调用方式如下:
- 调用 main api 这会给我一个对象数组。
- 对于数组中的每个对象,我必须异步调用另一个 API。
- 一旦对对象的子 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 中的状态。
这只是伪代码。
我有 API 调用方式如下:
- 调用 main api 这会给我一个对象数组。
- 对于数组中的每个对象,我必须异步调用另一个 API。
- 一旦对对象的子 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 中的状态。
这只是伪代码。