React Redux:如何依次调用多个相关动作

时间:2018-08-09 23:26:19

标签: reactjs redux react-redux redux-thunk

我正在尝试使用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变量始终为空。

我真的不确定该怎么办。相当常见的情况,但尚未找到解决方法。

2 个答案:

答案 0 :(得分:0)

我建议您使用另一个库来处理副作用,例如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
});

然后您可以在saga生成器中处理此操作:

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

答案 1 :(得分:0)

我对引入如此简单的框架不感兴趣。通勤回家后,一个念头打动了我。请让我知道优点/缺点。

新的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));
            }
        });
    };
};

这似乎为我提供了所需的一切。通过执行promise获取父记录,调度父子结果。