问题
I have a react saga code here which does not run in sequence:
yield put({ type: 'SHOW_LOADER', loading: 'workflowobject' }) #yield to initiate the loader
const states = yield call(() => axiosInstance.get(`/workflow-object/state/list/${action.workflow_id}/${action.workflow_object_id}/`))
const newState = states.data.map(item => ({ // some operation to shape my data , might this be the issue?
iteration: item.iteration,
...item.state
}));
yield put({ type: "STORE_WORKFLOW_DATA", payload: newState , fetch: 'workflowobject' , label: 'states'})
.....
bunch more of yields here
.....
yield put({ type: 'HIDE_LOADER', loading: 'workflowobject' }) #yield to change loader state
The problem here is that the HIDE_LOADER
gets called before some inbetween operations end , leading to a error found in my component
Here is my entire code snippet:
Saga
// This code loads the transitions and states for the detail page //
export function* workerWorkflowObjectDetail(action) {
try{
yield put({ type: 'SHOW_LOADER', loading: 'workflowobject' })
// clears the object states
yield put({ type: 'CLEAR_OBJECT_STATES' })
// store workflow_id
yield put({ type: "STORE_WORKFLOW_DATA", payload: action.workflow_id , fetch: 'workflowobject' , label: 'workflow_id'})
const transitions = yield call(axiosInstance.get , `/workflow-object/transition/list/${action.workflow_id}/${action.workflow_object_id}/`)
// store transitions
yield put({ type: "STORE_WORKFLOW_DATA", payload: transitions.data, fetch: 'workflowobject' , label: 'transitions'})
const newStateMap = {}
transitions.data.forEach(transition => {
if (transition.is_done) {
newStateMap[transition.source_state] = done_class
newStateMap[transition.destination_state] = selected_class
} else if (transition.is_cancelled) {
newStateMap[transition.destination_state] = cancelled_class
} else {
newStateMap[transition.destination_state] = default_class
}
});
// store state_class_mapping
yield put({ type: "STORE_WORKFLOW_DATA", payload: newStateMap, fetch: 'workflowobject' , label: 'state_class_mapping'})
const states = yield call(axiosInstance.get, `/workflow-object/state/list/${action.workflow_id}/${action.workflow_object_id}/`)
const newState = states.data.map(item => ({
iteration: item.iteration,
...item.state
}));
// stores states
yield put({ type: "STORE_WORKFLOW_DATA", payload: newState, fetch: 'workflowobject' , label: 'states'})
// stores object_id
yield put({ type: "STORE_WORKFLOW_DATA", payload: action.workflow_object_id, fetch: 'workflowobject' , label: 'object_identifier'})
// stores current_state
const current_state = yield call(axiosInstance.get,`/workflow-object/current-state/${action.workflow_id}/${action.workflow_object_id}/`)
yield put({ type: "STORE_WORKFLOW_DATA", payload: current_state.data, fetch: 'workflowobject' , label: 'current_state'})
// stores current iteration
const current_iteration = yield call(axiosInstance.get,`/workflow-object/current-iteration/${action.workflow_id}/${action.workflow_object_id}/`)
yield put({ type: "STORE_WORKFLOW_DATA", payload: current_iteration.data, fetch: 'workflowobject' , label: 'current_iteration'})
yield put({ type: 'HIDE_LOADER', loading: 'workflowobject' })
} catch(err){
console.log(err)
}
if (action.message) {
yield put({ type: "CREATE_MESSAGE", message: action.message })
}
}
Reducer
// Helpers
const storeData = (state, action) => {
switch (action.fetch) {
case 'workflowobject': return loadWorkflowObject(state, action)
}
}
const reducer = (state = initialState, action) => {
switch (action.type) {
case 'STORE_WORKFLOW_DATA': return storeData(state, action);
case 'CLEAR_OBJECT_STATES': return clearObjectStates(state, action);
default:
return state;
}
}
export default reducer;
回答1:
As per redux-saga
documentation, call(fn, ...args)
function should be provided with either a normal or a Generator function.
yield call(() => axiosInstance.get(`/workflow-object/state/list/${action.workflow_id}/${action.workflow_object_id}/`))
From you code it looks like the first parameter is neither a normal function that is returning a Promise nor a Generator function. If the result is not an Iterator object nor a Promise, the middleware will immediately return that value back to the saga, so that it can resume its execution synchronously. As per my understanding this could be the issue.
So instead of providing the arrow function which is calling the API, try providing this way,
yield call(axiosInstance.get, `/workflow-object/state/list/${action.workflow_id}/${action.workflow_object_id}/`)
Hope this helps in resolving the issue which you are facing.
来源:https://stackoverflow.com/questions/62300441/react-saga-yield-call-does-not-finish-before-next-code-is-run