React Saga Yield 调用在下一个代码运行之前没有完成 [英] React Saga Yield call does not finish before next code is run

查看:46
本文介绍了React Saga Yield 调用在下一个代码运行之前没有完成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我这里有一个不按顺序运行的 react saga 代码:

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

这里的问题是 HIDE_LOADER 在某些中间操作结束之前被调用,导致在我的组件中发现错误

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:

// 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 })
    }
}

减速器

// 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;

推荐答案

根据 redux-saga documentation, call(fn, ...args) 函数应提供普通或生成器函数.

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}/`))

从您的代码看来,第一个参数既不是返回 Promise 的普通函数,也不是生成器函数.如果结果既不是 Iterator 对象也不是 Promise,中间件将立即将该值返回给 saga,以便它可以同步恢复执行.根据我的理解,这可能是问题所在.

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.

因此,与其提供调用 API 的箭头函数,不如尝试提供这种方式,

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.

这篇关于React Saga Yield 调用在下一个代码运行之前没有完成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆