使用 redux-thunk 取消之前的获取请求
Cancel previous fetch request with redux-thunk
问题背景:
我正在构建一个 React/Redux 应用程序,它使用 redux-thunk 和 wretch(一个获取包装器)来处理异步请求。
我有一些搜索操作的加载时间可能会有很大差异,从而导致不良行为。
我研究过使用 AbortController(),但它要么完全取消我的所有请求,要么无法取消之前的请求。
示例问题:
- 请求搜索 "JOHN",然后请求搜索 "JOHNSON"。
- 首先是 "JOHNSON" return 的结果,然后是 "JOHN" return 的结果,然后覆盖 "JOHNSON" 结果。
目标:
启动请求应该会中止之前的待处理请求。
所需行为示例:
- 请求搜索 "JOHN",然后请求搜索 "JOHNSON"。
- 启动 "JOHNSON" 的请求后,"JOHN" 的待处理请求被中止。
代码:
actions.js
fetchData 操作通过 onClick 或其他函数调用。
import api from '../../utils/request';
export function fetchData(params) {
return dispatch => {
dispatch(requestData());
return api
.query(params)
.url('api/data')
.get()
.fetchError(err => {
console.log(err);
dispatch(apiFail(err.toString()));
})
.json(response => dispatch(receiveData(response.items, response.totalItems)))
}
}
export function requestData() {
return {
type: REQUEST_DATA,
waiting: true,
}
}
export function receiveData(items, totalItems) {
return {
type: RECEIVE_DATA,
result: items,
totalItems: totalItems,
waiting: false,
}
}
export function apiFail(err) {
return {
type: API_FAIL,
error: err,
waiting: false,
}
}
utils/request.js
这是糟糕的进口。 Wretch 是一个 fetch 包装器,因此它的功能应该与 fetch 类似。
import wretch from 'wretch';
/**
* Handles Server Error
*
* @param {object} err HTTP Error
*
* @return {undefined} Returns undefined
*/
function handleServerError(err) {
console.error(err);
}
const api = wretch()
.options({ credentials: 'include', mode: 'cors' })
.url(window.appBaseUrl || process.env.REACT_APP_API_HOST_NAME)
.resolve(_ => _.error(handleServerError))
export default api;
尝试:
我试过将 wretch 的 .signal() 参数与 AbortController() 一起使用,在请求后调用 .abort(),但这会中止所有请求,导致我的应用程序中断。示例如下:
import wretch from 'wretch';
/**
* Handles Server Error
*
* @param {object} err HTTP Error
*
* @return {undefined} Returns undefined
*/
function handleServerError(err) {
console.error(err);
}
const controller = new AbortController();
const api = wretch()
.signal(controller)
.options({ credentials: 'include', mode: 'cors' })
.url(window.appBaseUrl || process.env.REACT_APP_API_HOST_NAME)
.resolve(_ => _.error(handleServerError))
controller.abort();
export default api;
我试过将逻辑移动到不同的地方,但它似乎中止了所有操作或中止了其中的 none 个。
任何有关如何解决此问题的建议都将不胜感激,这对我的团队至关重要。
谢谢
我现在觉得很傻,但这就是让它工作所需要的。
求解步骤:
- 将 AbortController 设置为减速器的初始状态
reducer.js
export default (state = {
controller: new AbortController(),
}, action) => {
switch (action.type) {
...
- 在获取操作开始时从状态中获取 AbortController 并中止它。
- 创建一个新的 AbortController 并将其传递到 requestData 操作中。
- 将新的 AbortController 传递到 wretch 调用的
signal()
参数中。
actions.js
export function fetchData(params) {
return (dispatch, getState) => {
const { controller } = getState().reducer;
controller.abort();
const newController = new AbortController();
dispatch(requestData(newController));
return api
.signal(newController)
.query(params)
.url('api/data')
.get()
.fetchError(err => {
console.log(err);
dispatch(apiFail(err.toString()));
})
.json(response => dispatch(receiveData(response.items, response.totalItems)))
}
}
export function requestData(controller) {
return {
type: REQUEST_DATA,
waiting: true,
controller,
}
}
在reducer中,对于requestData action的情况,将新的AbortController设置为state。
reducer.js
case REQUEST_DATA:
return {
...state,
waiting: action.waiting,
controller: action.controller
};
wretch 有一些额外的功能,一个 .onAbort()
参数,允许您在请求中止时分派其他操作。我还没有把它编码出来,但我想我会为其他遇到这个问题的人提供信息。
问题背景:
我正在构建一个 React/Redux 应用程序,它使用 redux-thunk 和 wretch(一个获取包装器)来处理异步请求。
我有一些搜索操作的加载时间可能会有很大差异,从而导致不良行为。
我研究过使用 AbortController(),但它要么完全取消我的所有请求,要么无法取消之前的请求。
示例问题:
- 请求搜索 "JOHN",然后请求搜索 "JOHNSON"。
- 首先是 "JOHNSON" return 的结果,然后是 "JOHN" return 的结果,然后覆盖 "JOHNSON" 结果。
目标:
启动请求应该会中止之前的待处理请求。
所需行为示例:
- 请求搜索 "JOHN",然后请求搜索 "JOHNSON"。
- 启动 "JOHNSON" 的请求后,"JOHN" 的待处理请求被中止。
代码:
actions.js
fetchData 操作通过 onClick 或其他函数调用。
import api from '../../utils/request';
export function fetchData(params) {
return dispatch => {
dispatch(requestData());
return api
.query(params)
.url('api/data')
.get()
.fetchError(err => {
console.log(err);
dispatch(apiFail(err.toString()));
})
.json(response => dispatch(receiveData(response.items, response.totalItems)))
}
}
export function requestData() {
return {
type: REQUEST_DATA,
waiting: true,
}
}
export function receiveData(items, totalItems) {
return {
type: RECEIVE_DATA,
result: items,
totalItems: totalItems,
waiting: false,
}
}
export function apiFail(err) {
return {
type: API_FAIL,
error: err,
waiting: false,
}
}
utils/request.js
这是糟糕的进口。 Wretch 是一个 fetch 包装器,因此它的功能应该与 fetch 类似。
import wretch from 'wretch';
/**
* Handles Server Error
*
* @param {object} err HTTP Error
*
* @return {undefined} Returns undefined
*/
function handleServerError(err) {
console.error(err);
}
const api = wretch()
.options({ credentials: 'include', mode: 'cors' })
.url(window.appBaseUrl || process.env.REACT_APP_API_HOST_NAME)
.resolve(_ => _.error(handleServerError))
export default api;
尝试:
我试过将 wretch 的 .signal() 参数与 AbortController() 一起使用,在请求后调用 .abort(),但这会中止所有请求,导致我的应用程序中断。示例如下:
import wretch from 'wretch';
/**
* Handles Server Error
*
* @param {object} err HTTP Error
*
* @return {undefined} Returns undefined
*/
function handleServerError(err) {
console.error(err);
}
const controller = new AbortController();
const api = wretch()
.signal(controller)
.options({ credentials: 'include', mode: 'cors' })
.url(window.appBaseUrl || process.env.REACT_APP_API_HOST_NAME)
.resolve(_ => _.error(handleServerError))
controller.abort();
export default api;
我试过将逻辑移动到不同的地方,但它似乎中止了所有操作或中止了其中的 none 个。
任何有关如何解决此问题的建议都将不胜感激,这对我的团队至关重要。
谢谢
我现在觉得很傻,但这就是让它工作所需要的。
求解步骤:
- 将 AbortController 设置为减速器的初始状态
reducer.js
export default (state = {
controller: new AbortController(),
}, action) => {
switch (action.type) {
...
- 在获取操作开始时从状态中获取 AbortController 并中止它。
- 创建一个新的 AbortController 并将其传递到 requestData 操作中。
- 将新的 AbortController 传递到 wretch 调用的
signal()
参数中。
actions.js
export function fetchData(params) {
return (dispatch, getState) => {
const { controller } = getState().reducer;
controller.abort();
const newController = new AbortController();
dispatch(requestData(newController));
return api
.signal(newController)
.query(params)
.url('api/data')
.get()
.fetchError(err => {
console.log(err);
dispatch(apiFail(err.toString()));
})
.json(response => dispatch(receiveData(response.items, response.totalItems)))
}
}
export function requestData(controller) {
return {
type: REQUEST_DATA,
waiting: true,
controller,
}
}
在reducer中,对于requestData action的情况,将新的AbortController设置为state。
reducer.js
case REQUEST_DATA:
return {
...state,
waiting: action.waiting,
controller: action.controller
};
wretch 有一些额外的功能,一个 .onAbort()
参数,允许您在请求中止时分派其他操作。我还没有把它编码出来,但我想我会为其他遇到这个问题的人提供信息。