React Redux:如何按顺序调用多个依赖动作

React Redux: How to call multiple dependent actions in sequence

我正在尝试使用 thunk 在单个操作中链接两个调用,但它似乎没有按预期工作。我需要第一个操作的 ID 值来调用第二个操作。

操作如下所示:

export const getParentRecords = filterId => {
    return (dispatch, getState) => {
        let headers = {
            filter_id: filterId
        };
        const request = axios({
            method: "GET",
            url: `https://myapi.com/v1/parent-records`,
            headers: headers
        });
        dispatch({
            type: GET_PARENT_RECORDS,
            payload: request
        });
    };
};

export const getChildRecords = (parentId = null) => {
    let url = `https://myapi.com/v1/child-records`;
    if (parentId) {
        url = `https://myapi.com/v1/child-records/?parent_id=${parentId}`;
    }
    return (dispatch, getState) => {
        let headers = {
            //etc...
        };
        const request = axios({
            method: "GET",
            url: url,
            headers: headers
        });
        dispatch({
            type: GET_CHILD_RECORDS,
            payload: request
        });
    };
};

export const getAllRecords = filterId => {
    return (dispatch, getState) => {
        dispatch(getParentRecords(filterId);
        let { parentRecords } = getState();
        let defaultParent = parentRecords.filter(p => p.is_default === true)[0];
        dispatch(getChildRecords(defaultParent.parent_id));
    };
};

在调用组件中:

const mapStateToProps = state => {
    return {
        parentRecords: state.parentRecords,
        childRecords: state.childRecords
    };
};

export default connect(mapStateToProps, { getAllRecords })(MyComponent);

问题是;调度第一个动作似乎没有做任何事情。当我之后调用 getState() 时,数据不存在。 getAllRecords 中的 parentRecords 变量始终为空。

我真的不知道该怎么办。很常见的情况,但还没有找到解决办法。

我建议您使用另一个库来处理副作用,例如 redux-sagaredux-observable,因为 redux-thunk 非常原始。

Redux-saga 是基于生成器的命令式的。 Redux-observable 是基于 RxJS 的声明式的。 所以选择你更喜欢的。

https://redux-saga.js.org/

https://redux-observable.js.org/


每个异步操作应具有三种操作类型,例如:GET_CHILD_RECORDSGET_CHILD_RECORDS_SUCCESSGET_CHILD_RECORDS_FAILURE

使用 redux-saga 看起来像这样:

动作创作者:

const getChildRecords = (parentId = null) => ({
  type: GET_PARENT_RECORDS,
  payload: parentId
});

然后你可以在传奇生成器中处理这个动作:

function rootSaga*() {
  yield takeLatest(GET_PARENT_RECORDS, onGetParentRecords);
  yield takeLatest(GET_PARENT_RECORDS_SUCCESS, onGetChildRecords);
}

function onGetParentRecords*({ payload: parentId }) {
  try {
    const parentRecords = yield call(apiCallFunctionHere, parentId);
    yield put({
      type: GET_PARENT_RECORDS_SUCCESS,
      payload: parentRecords
    });
  } catch(error) {
    yield put({
      type: GET_PARENT_RECORDS_FAILURE,
      error
    });
  }
}

function onGetChildRecords*({ payload: parentRecords }) {
  const defaultParent = parentRecords.filter(p => p.is_default === true)[0];
  try {
    const childRecords = call(apiFunctionToFetchChildRecords, defaultParent);
    yield put({
      type: GET_CHILDREN_RECORDS_SUCCESS,
      payload: parentRecords
    });
  } catch(error) {
    yield put({
      type: GET_CHILDREN_RECORDS_FAILURE,
      error
    });
  }
}

我不想为如此简单的事情引入另一个框架。通勤回家后,我突然想到一个主意。请让我知道 pros/cons.

一个新的 getAllRecords 函数:

export const getAllRecords = filterId => {
    return (dispatch, getState) => {
        let headers = {
            // etc...
        };
        const request = axios({
            method: "GET",
            url: `https://myapi.com/v1/parent-records`,
            headers: headers
        });
        request.then(result => {
            if (result.status === 200) {
                let parentRecords = result.data.payload;
                let defaultParent = parentRecords.filter(p => p.is_default === true)[0];
                dispatch({
                    type: GET_PARENT_RECORDS,
                    payload: parentRecords
                });
                dispatch(getChildRecords(defaultParent.parent_id));
            }
        });
    };
};

这似乎让我得到了我需要的一切。通过执行承诺获取父记录,分派父结果和子结果。