首页 > 解决方案 > 如何使用 Abort Controller 中止从 useEffect 内部启动但由用户操作触发的 API?

问题描述

  1. 我在 useEffect 挂钩中调用了一组 API。
  2. 但是如果用户点击cancel按钮。我希望 controller.abort() 触发以取消所有 API 调用(让我们将此方法称为*cancelAllCalls*()

问题:(1)我必须在 useEffect 之外启动 controller.abort()。>> 这个需要的控制器变量可以在内部访问*cancelAllCalls()*-不工作

(2)如果我尝试做一个setState内部*cancelAllCalls()*并将其添加为useEffect调用中的依赖项,controller.abort()它仍然会重新启动控制器并且传递给 API 的信号也会改变 -不工作

注意:我可以通过cancel仅在 useEffect 内的按钮上添加一个 eventListner 来实现它(并且我确保它仅通过使用标志发生一次)然后controller .abort()在其中调用。但我对这种方法并不十分满意。

这里有什么建议/指导吗?

标签: javascriptreactjsreact-hookses6-promise

解决方案


你可以这样做:

function TestComponent(props) {
  const ref = React.useRef(null);
  
  React.useEffect(() => {
    ref.current= new AbortController;
    return () => (ref.current.abort());
  }, []);

  const cancelAllCalls= ()=>{
    ref.current.abort();
    ref.current= new AbortController();
  }

  // your hooks
  React.useEffect(() => {
     //..
  }, [myVar])

  return ()
}

或者像这样(现场演示):

import React from "react";
import { useAsyncEffect } from "use-async-effect2";
import cpAxios from "cp-axios";

// Note: the related network request will also be aborted

function TestComponent(props) {
  const [cancel, done, result, err] = useAsyncEffect(
    function* () {
      return (yield cpAxios(props.url).timeout(props.timeout)).data;
    },
    { states: true, deps: [props.url] }
  );

  return (
    <div>
      <div>
        {done ? (err ? err.toString() : JSON.stringify(result)) : "loading..."}
      </div>
      <button onClick={cancel} disabled={done}>
        Cancel async effect
      </button>
    </div>
  );
}

推荐阅读