'imported' 异步函数上的 useEffect 清理

useEffect cleanup on 'imported' async function

请不要认为这是重复的。我已经搜索了很多博客和资料,但还没有找到解决方案。

首先我的问题是'how to resolve react state change in unmounted component error, and cancel an async function call that is imported within the useEffect hook?'

我知道您可以通过使用 useEffect 中的清理功能解决“state changed in an unmounted component”错误。在 useEffect 挂钩中进行异步调用的情况下,您可以执行 clearTimeout,为 Axios 使用取消令牌,创建 [isMounted] 状态以标记 mounted/unmounted 状态等。所以,至少,我知道如何隐藏反应警告

但是,我的老板不仅要隐藏警告,还要取消异步请求。这是代码的简化版本。

import { fetchFunction } from '../../../somewhereInTheDir';

function Page() {
  const [data, setData] = useState([]);
  const [isMounted, setIsMounted] = useState(true);

  async function fetchData() {
    try {
      const data = await fetchFunction(someUri);

      setData(data);
    } catch (error) {
      console.warn(error);
    }
  }

  useEffect(() => {
    if(isMounted) {
      fetchData(ENDPOINT);
    }
    
    return () => {
      setIsMounted(false);
    }
  })
}

isMounted 状态掩盖了警告。所以我在控制台中什么也看不到,这是一个好兆头。但是这段代码不会 block/cancel 页面组件卸载时来自端点的数据。而且你不能使用像在 http header 中放置取消令牌这样的策略,因为 fetchFunction 来自外部。

ps。我的老板说使用 isMounted 状态就好像它是一个 JavaScript 变量可能是来自 React 的 anti-pattern,因为 React 状态变化导致 re-rendering。有没有更好的方法在不使用 isMounted 状态的情况下隐藏警告?

关于你问题的最后一段,你可以用refs代替state。

const isMounted = useRef(false)

useEffect(() => {
    isMounted.current = true
    return () => isMounted.current=false
}, [])

您可以试试这个方法。在挂钩本身以及条件 setState 函数中跟踪挂载状态。

另外,包含空的依赖项数组也很重要,否则您的组件将在每次渲染时调用挂钩。

import { fetchFunction } from '../../../somewhereInTheDir';

function Page() {
  const [data, setData] = useState([]);
  const [isMounted, setIsMounted] = useState(true);

  async function fetchData() {
    try {
      return await fetchFunction(someUri);
    } catch (error) {
      console.warn(error);
    }
  }

useEffect(() => { // <- you can't change this to async
  let mounted = true

    // Variant with Promise
    fetchData(ENDPOINT).then(data => {
      if (mounted) setData(data);
    })

    // Variant with async/await
    (async () => {
      const data = await fetchData(ENDPOINT)
      if (mounted) setData(data);
    }())
    
    return () => {
      mounted = false
    }
  }, []) // <- empty dependency array is important here
}

下面的文章介绍了一些其他方法,即使您使用多个 useEffect hook 等,如何处理挂载状态

https://www.benmvp.com/blog/handling-async-react-component-effects-after-unmount/