admin管理员组文章数量:1355694
I have a Saga where I need to do 3 asynchronous requests, then use the responses from the 3 requests in a follow-up request. Here's some psuedo-code to explain:
function* useOtherActionsAndSagas(action) {
try {
const [response1, response2, response3] = yield [
request1,
request2,
request3
];
const orderData = {
...response1,
...response2,
...response3,
};
const response4 = yield request4;
yield put({ type: 'SUCCESS', data: response4 });
} catch (e) {
// handle error
}
The 3 requests request1
, request2
and request3
correspond to 3 separate Sagas. For example, for request1
there's a Saga along the lines of:
export function* request1(action) {
try {
const result = yield api.get(`/api/endpoint`);
yield put({...action, type: ACTION1_SUCCESS, data: result});
} catch (e) {
yield put({...action, type: ACTION1_FAIL, errors: e});
}
}
function* watchAction1() {
yield* takeLatest(ACTION1, request1);
}
export default function* () {
yield [fork(watchAction1)];
}
where api.get
is a wrapper for Axios.get().
This watcher in that Saga is connected to a corresponding action/reducer.
export const ACTION1 = "actions/ACTION1";
export const ACTION1_SUCCESS = "actions/ACTION1_SUCCESS";
export const ACTION1_FAIL = "actions/ACTION1_FAIL";
const initialState = {
// Initial state
};
export default function reducer(state = initialState, action = {}) {
switch (action.type) {
case ACTION1:
// return state
case ACTION1_SUCCESS:
// return state
case ACTION1_FAIL:
// return state
};
default:
// return state;
}
}
export function request1(data) { return {type: ACTION1, data}; }
To keep my code DRY I was hoping to take advantage of the existing action and saga in the parent saga. To do this I tried:
const [response1, response2, response3] = yield [
put({type: ACTION1, data: data1}),
put({type: ACTION2, data: data2}),
put({type: ACTION3, data: data3})
];
This correctly initiates each action and their corresponding sagas. However, the response from the requests are not available in the assigned variables. That is, response1
, response2
and response3
are references to their actions {type: "actions/ACTION1", data: data1}
and not a Promise.
I know it would be possible to duplicate the Axios requests in this parent Saga but I'd lose the bonus of having the success/fail actions for the individual requests.
Is it possible to use a setup like this? If so, how can the responses from the asynchronous requests be retrieved for use in a follow-up request?
If not, what is the correct method for acplishing this?
Update
I can use the workers from the other Sagas within the parent saga, like this:
import request1 from request1Saga;
const [response1, response2, response3] = yield [
call(request1, data1),
call(request2, data2),
call(request3, data3),
];
where request1
, request2
and request3
are the worker functions from other Sagas. That gives the benefit of the ACTION1_SUCCESS
and ACTION1_FAIL
actions from those Sagas being used.
I have a Saga where I need to do 3 asynchronous requests, then use the responses from the 3 requests in a follow-up request. Here's some psuedo-code to explain:
function* useOtherActionsAndSagas(action) {
try {
const [response1, response2, response3] = yield [
request1,
request2,
request3
];
const orderData = {
...response1,
...response2,
...response3,
};
const response4 = yield request4;
yield put({ type: 'SUCCESS', data: response4 });
} catch (e) {
// handle error
}
The 3 requests request1
, request2
and request3
correspond to 3 separate Sagas. For example, for request1
there's a Saga along the lines of:
export function* request1(action) {
try {
const result = yield api.get(`/api/endpoint`);
yield put({...action, type: ACTION1_SUCCESS, data: result});
} catch (e) {
yield put({...action, type: ACTION1_FAIL, errors: e});
}
}
function* watchAction1() {
yield* takeLatest(ACTION1, request1);
}
export default function* () {
yield [fork(watchAction1)];
}
where api.get
is a wrapper for Axios.get().
This watcher in that Saga is connected to a corresponding action/reducer.
export const ACTION1 = "actions/ACTION1";
export const ACTION1_SUCCESS = "actions/ACTION1_SUCCESS";
export const ACTION1_FAIL = "actions/ACTION1_FAIL";
const initialState = {
// Initial state
};
export default function reducer(state = initialState, action = {}) {
switch (action.type) {
case ACTION1:
// return state
case ACTION1_SUCCESS:
// return state
case ACTION1_FAIL:
// return state
};
default:
// return state;
}
}
export function request1(data) { return {type: ACTION1, data}; }
To keep my code DRY I was hoping to take advantage of the existing action and saga in the parent saga. To do this I tried:
const [response1, response2, response3] = yield [
put({type: ACTION1, data: data1}),
put({type: ACTION2, data: data2}),
put({type: ACTION3, data: data3})
];
This correctly initiates each action and their corresponding sagas. However, the response from the requests are not available in the assigned variables. That is, response1
, response2
and response3
are references to their actions {type: "actions/ACTION1", data: data1}
and not a Promise.
I know it would be possible to duplicate the Axios requests in this parent Saga but I'd lose the bonus of having the success/fail actions for the individual requests.
Is it possible to use a setup like this? If so, how can the responses from the asynchronous requests be retrieved for use in a follow-up request?
If not, what is the correct method for acplishing this?
Update
I can use the workers from the other Sagas within the parent saga, like this:
import request1 from request1Saga;
const [response1, response2, response3] = yield [
call(request1, data1),
call(request2, data2),
call(request3, data3),
];
where request1
, request2
and request3
are the worker functions from other Sagas. That gives the benefit of the ACTION1_SUCCESS
and ACTION1_FAIL
actions from those Sagas being used.
- Which version of redux-saga are you using? I think from v0.15.0 they use yield all([]) now Have a look at - github./redux-saga/redux-saga/blob/… – Sudheer Commented Jun 12, 2017 at 12:00
- Currently on 0.12.1, I can update but I don't think that will fix the issue of the responses. – Brett DeWoody Commented Jun 12, 2017 at 12:06
- Ya I dont think it will make any difference. One more thing though isn't yield [] looking for promise object? here you have just state return though. – Sudheer Commented Jun 12, 2017 at 12:10
- Yes, that's the crux of the issue I think. I want to reuse the external action/saga to take advantage of their success/fail actions, as well as not duplicate the existing request already in another saga. – Brett DeWoody Commented Jun 12, 2017 at 12:17
-
1
I suppose that will work if I passed the Saga worker from the sub-sagas to each
fork()
. I'm doing something similar with the array of requests now. – Brett DeWoody Commented Jun 12, 2017 at 12:54
1 Answer
Reset to default 3All you need is bine all
binator with call
effect (docs for posing sagas and running tasks in parallel):
const [response1, response2, response3] = yield all([
call(request1),
call(request2),
call(request3)
]);
This will execute sagas in parallel and return results from each of them. It works as Promise.all
.
The sagas above (request1 to request3) need to return some data at the end of saga:
export function* request1(action) {
try {
const result = yield call(url => api.get(url), `/api/endpoint`);
yield put({...action, type: ACTION1_SUCCESS, data: result});
// This will be assigned to result1
return result
} catch (e) {
yield put({...action, type: ACTION1_FAIL, errors: e});
}
}
Note: You don't need to fork takeEvery, because it is already "forked":
// Example of root saga:
export default function* () {
yield takeLatest(ACTION1, request1);
yield takeLatest(ACTION2, request2);
// ...
}
本文标签: javascriptUsing ActionSaga in another SagaStack Overflow
版权声明:本文标题:javascript - Using ActionSaga in another Saga - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1743987132a2571470.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论