使用 redux-thunk 取消之前的 fetch 请求
Posted
技术标签:
【中文标题】使用 redux-thunk 取消之前的 fetch 请求【英文标题】:Cancel previous fetch request with redux-thunk 【发布时间】:2020-06-05 05:52:16 【问题描述】:问题背景:
我正在构建一个 React/Redux 应用程序,它使用 redux-thunk 和 wretch(一个 fetch 包装器)来处理异步请求。
我有一些搜索操作,它们的加载时间可能会有很大差异,从而导致不良行为。
我已经研究过使用 AbortController(),但它要么完全取消我的所有请求,要么无法取消之前的请求。
示例问题:
请求搜索“JOHN”,然后请求搜索“JOHNSON”。 “JOHNSON”的结果首先返回,“JOHN”的结果稍后返回并覆盖“JOHNSON”的结果。目标:
发起请求应该中止之前的未决请求。
示例期望行为:
请求搜索“JOHN”,然后请求搜索“JOHNSON”。 在发起对“JOHNSON”的请求后,对“JOHN”的挂起请求被中止。代码:
actions.js
通过 onClick 或其他函数调用 fetchData 操作。
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;
我已经尝试将逻辑移动到不同的地方,但它似乎中止所有操作或不中止任何操作。
任何有关如何解决此问题的建议都将不胜感激,这对我的团队至关重要。
谢谢
【问题讨论】:
这是 sagas 做得非常好的事情:redux-saga.js.org 我很感谢您的意见,但我担心鉴于我们有限的时间和资源,切换到 redux-saga 将需要重新构建。 【参考方案1】:我现在觉得很傻,但这就是让它发挥作用的原因。
解决步骤:
将 AbortController 设置为 reducer 的初始状态reducer.js
export default (state =
controller: new AbortController(),
, action) =>
switch (action.type)
...
从状态中获取 AbortController,在 fetch 操作的开始并中止它。
创建一个新的 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设置为状态。
reducer.js
case REQUEST_DATA:
return
...state,
waiting: action.waiting,
controller: action.controller
;
wretch 还有一些额外的功能,一个.onAbort()
参数,允许您在请求中止时调度其他操作。我还没有把它写出来,但我想我会为其他为此苦苦挣扎的人提供信息。
【讨论】:
以上是关于使用 redux-thunk 取消之前的 fetch 请求的主要内容,如果未能解决你的问题,请参考以下文章