我正在尝试下面的useEffect示例:

useEffect(async () => {
    try {
        const response = await fetch(`https://www.reddit.com/r/${subreddit}.json`);
        const json = await response.json();
        setPosts(json.data.children.map(it => it.data));
    } catch (e) {
        console.error(e);
    }
}, []);

我在控制台得到这个警告。但我认为,对于异步调用,清理是可选的。我不知道为什么我得到这个警告。链接沙盒为例。https://codesandbox.io/s/24rj871r0p


当前回答

其他答案已经有很多例子给出了,并且解释得很清楚,所以我将从TypeScript类型定义的角度来解释它们。

useEffect钩子TypeScript签名:

function useEffect(effect: EffectCallback, deps?: DependencyList): void;

效果类型:

// NOTE: callbacks are _only_ allowed to return either void, or a destructor.
type EffectCallback = () => (void | Destructor);

// Destructors are only allowed to return void.
type Destructor = () => void | { [UNDEFINED_VOID_ONLY]: never };

现在我们应该知道为什么effect不能是一个异步函数了。

useEffect(async () => {
  //...
}, [])

async函数将返回一个带有隐式未定义值的JS promise。这不是useEffect的期望。

其他回答

其他答案已经有很多例子给出了,并且解释得很清楚,所以我将从TypeScript类型定义的角度来解释它们。

useEffect钩子TypeScript签名:

function useEffect(effect: EffectCallback, deps?: DependencyList): void;

效果类型:

// NOTE: callbacks are _only_ allowed to return either void, or a destructor.
type EffectCallback = () => (void | Destructor);

// Destructors are only allowed to return void.
type Destructor = () => void | { [UNDEFINED_VOID_ONLY]: never };

现在我们应该知道为什么effect不能是一个异步函数了。

useEffect(async () => {
  //...
}, [])

async函数将返回一个带有隐式未定义值的JS promise。这不是useEffect的期望。

请试试这个

 useEffect(() => {
        (async () => {
          const products = await api.index()
          setFilteredProducts(products)
          setProducts(products)
        })()
      }, [])

你也可以使用IIFE格式来保持内容简短

function Example() {
    const [data, dataSet] = useState<any>(null)

    useEffect(() => {
        (async () => {
            let response = await fetch('api/data')
            response = await response.json()
            dataSet(response);
        })();
    }, [])

    return <div>{JSON.stringify(data)}</div>
}

最简单的方法是使用use-async-effect中的useAsyncEffect 你可以在NPM上找到它。

const ProtectedRoute = ({ children }) => {

    const [isAuth, setIsAuth] = useState(false);

    useAsyncEffect(async () => {
        try {
            const data = await axios("auth");
            console.log(data);
            setIsAuth(true);
        } catch (error) {
            console.log(error);
        }
    }, []);



    if (!isAuth)
        return <Navigate to="/signin" />

    return children;

}

只是一个关于purescript语言如何AWESOME处理这个问题的陈腐效果与Aff单子

没有PURESCRIPT

你必须使用AbortController

function App() {
    const [ data, setData ] = React.useState([]);

    React.useEffect(() => {
        const abortController = new AbortController();
        void async function fetchData() {
            try {
                const url = 'https://jsonplaceholder.typicode.com/todos/1';
                const response = await fetch(url, { signal: abortController.signal });
                setData(await response.json());
            } catch (error) {
                console.log('error', error);
            }
        }();
        return () => {
            abortController.abort(); // cancel pending fetch request on component unmount
        };
    }, []);

    return <pre>{JSON.stringify(data, null, 2)}</pre>;
}

或者陈旧(来自NoahZinsmeister/web3-react的例子)

function Balance() {
  const { account, library, chainId } = useWeb3React()

  const [balance, setBalance] = React.useState()
  React.useEffect((): any => {
    if (!!account && !!library) {      
      let stale = false
      
      library 
        .getBalance(account)
        .then((balance: any) => {
          if (!stale) {
            setBalance(balance)
          }
        })
        .catch(() => {
          if (!stale) {
            setBalance(null)
          }
        })

      return () => { // NOTE: will be called every time deps changes
        stale = true
        setBalance(undefined)
      }
    }
  }, [account, library, chainId]) // ensures refresh if referential identity of library doesn't change across chainIds

  ...

与PURESCRIPT

检查如何useAff杀死它的Aff在清理功能

Aff被实现为一个状态机(没有承诺)

但与我们相关的是:

你可以把你的AbortController放在这里 如果错误被抛出到光纤或光纤内部,它将停止运行Effects(未测试)和Affs(从第二个例子开始,它将不运行,因此它将not setBalance(balance))