javascript - 使用 redux-thunk 取消之前的 fetch 请求

标签 javascript reactjs redux fetch redux-thunk

问题背景:

我正在构建一个使用 redux-thunk 和 wretch(提取包装器)来处理异步请求的 React/Redux 应用程序。

我有一些搜索操作,它们的加载时间可能会有很大差异,从而导致不良行为。

我已经研究过使用 AbortController(),但它要么完全取消我的所有请求,要么无法取消之前的请求。

示例问题:

  • 请求搜索“JOHN”,然后请求搜索“JOHNSON”。
  • “JOHNSON”的结果首先返回,“JOHN”的结果稍后返回并覆盖“JOHNSON”的结果。

  • 目标:

    发起请求应中止先前的未决请求。

    示例期望的行为:
  • 请求搜索“JOHN”,然后请求搜索“JOHNSON”。
  • 在发起对“JOHNSON”的请求时,对“JOHN”的未决请求被中止。

  • 代码:

    Action .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,
      }
    }
    

    实用程序/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;
    

    我已经尝试将逻辑移动到各个地方,但它似乎中止了所有操作或没有中止任何操作。

    任何有关如何解决此问题的建议都将不胜感激,这对我的团队至关重要。

    谢谢

    最佳答案

    我现在觉得很傻,但这就是让它工作的原因。

    解决步骤:

  • 将 AbortController 设置为 reducer 的初始状态

  • reducer .js
    export default (state = {
      controller: new AbortController(),
    }, action) => {
      switch (action.type) {
        ...
    
  • 在 fetch 操作开始时从状态中获取 AbortController 并中止它。
  • 创建一个新的 AbortController 并将其传递给 requestData 操作。
  • 将新的 AbortController 传递到 signal()可怜的电话的参数。

  • Action .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()参数,允许您在请求中止时调度其他操作。我还没有把它编码出来,但我想我会把这些信息包括在其他任何为此苦苦挣扎的人身上。

    关于javascript - 使用 redux-thunk 取消之前的 fetch 请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60327829/

    相关文章:

    javascript - 填充下拉列表选择

    javascript - 如何提高该功能的性能?

    javascript - Meteor 中的模板级订阅

    javascript - Redux 字段中输入的第一个字母大写

    reactjs - 使用 redux 工具包时定义操作中的副作用(不是异步 thunk)的正确方法是什么?

    javascript - 使用 ng-style 设置样式后悬停时更改背景颜色

    javascript - 比较两个数组并向另一个数组添加对象

    javascript - 来自react-bootstrap的ListGroupItem和Button在同一行

    javascript - React Native 应用程序中 Redux thunk 的奇怪行为

    reactjs - creactAsyncThunk 中的 action.payload 未定义