React Saga Yield call does not finish before next code is run

回眸只為那壹抹淺笑 提交于 2020-06-29 04:06:13

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!