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-saga
或 redux-observable
,因为 redux-thunk
非常原始。
Redux-saga 是基于生成器的命令式的。
Redux-observable 是基于 RxJS 的声明式的。
所以选择你更喜欢的。
https://redux-observable.js.org/
每个异步操作应具有三种操作类型,例如:GET_CHILD_RECORDS
、GET_CHILD_RECORDS_SUCCESS
和 GET_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));
}
});
};
};
这似乎让我得到了我需要的一切。通过执行承诺获取父记录,分派父结果和子结果。
我正在尝试使用 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-saga
或 redux-observable
,因为 redux-thunk
非常原始。
Redux-saga 是基于生成器的命令式的。 Redux-observable 是基于 RxJS 的声明式的。 所以选择你更喜欢的。
https://redux-observable.js.org/
每个异步操作应具有三种操作类型,例如:GET_CHILD_RECORDS
、GET_CHILD_RECORDS_SUCCESS
和 GET_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));
}
});
};
};
这似乎让我得到了我需要的一切。通过执行承诺获取父记录,分派父结果和子结果。