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 accomplishing 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.
call(subSagaWorker)
within the array of requests. – Gibefork()
. I'm doing something similar with the array of requests now. – Gibe