Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 使用redux thunk取消以前的提取请求_Javascript_Reactjs_Redux_Fetch_Redux Thunk - Fatal编程技术网

Javascript 使用redux thunk取消以前的提取请求

Javascript 使用redux thunk取消以前的提取请求,javascript,reactjs,redux,fetch,redux-thunk,Javascript,Reactjs,Redux,Fetch,Redux Thunk,问题背景: 我正在构建一个React/Redux应用程序,它使用reduxtunk和wretch(一个获取包装器)来处理异步请求 我有一些搜索操作,它们的加载时间可能会有很大的变化,从而导致不良行为 我已经研究过使用AbortController(),但它要么直接取消我的所有请求,要么无法取消以前的请求 示例问题: 请求搜索“JOHN”,然后请求搜索“JOHNSON” “JOHNSON”的结果首先返回,然后“JOHN”的结果稍后返回并覆盖“JOHNSON”结果 目标: 启动请求应中止以前的挂

问题背景:

我正在构建一个React/Redux应用程序,它使用reduxtunk和wretch(一个获取包装器)来处理异步请求

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

我已经研究过使用AbortController(),但它要么直接取消我的所有请求,要么无法取消以前的请求

示例问题:

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

启动请求应中止以前的挂起请求

所需行为示例:

  • 请求搜索“JOHN”,然后请求搜索“JOHNSON”
  • 启动“JOHNSON”请求后,挂起的“JOHN”请求被中止
代码:

actions.js

export default (state = {
  controller: new AbortController(),
}, action) => {
  switch (action.type) {
    ...
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,
  }
}
case REQUEST_DATA:
  return {
    ...state,
    waiting: action.waiting,
    controller: action.controller
  };
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

export default (state = {
  controller: new AbortController(),
}, action) => {
  switch (action.type) {
    ...
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,
  }
}
case REQUEST_DATA:
  return {
    ...state,
    waiting: action.waiting,
    controller: action.controller
  };
这是卑鄙的进口货。Wreth是一个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.js

export default (state = {
  controller: new AbortController(),
}, action) => {
  switch (action.type) {
    ...
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,
  }
}
case REQUEST_DATA:
  return {
    ...state,
    waiting: action.waiting,
    controller: action.controller
  };
  • 在获取操作开始时,从状态获取AbortController并中止它
  • 创建一个新的AbortController并将其传递到requestData操作中
  • 将新的AbortController传递到Wreth调用的
    信号()
    参数中
actions.js

export default (state = {
  controller: new AbortController(),
}, action) => {
  switch (action.type) {
    ...
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,
  }
}
case REQUEST_DATA:
  return {
    ...state,
    waiting: action.waiting,
    controller: action.controller
  };
在reducer中,对于requestData操作,将新的AbortController设置为状态

reducer.js

export default (state = {
  controller: new AbortController(),
}, action) => {
  switch (action.type) {
    ...
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,
  }
}
case REQUEST_DATA:
  return {
    ...state,
    waiting: action.waiting,
    controller: action.controller
  };

wretch还有一些附加功能,它是一个
.onAbort()
参数,允许您在请求中止时分派其他操作。我还没有把它编码出来,但我想我会把其他人的信息包括进来。这是sagas做得很好的一件事:我很欣赏他们的意见,但我担心,鉴于我们有限的时间和资源,切换到redux saga将是一次太多的重建。