【问题标题】:How to fix React WArning : Can't perform a React state update on an unmounted component如何修复 React 警告:无法在未安装的组件上执行 React 状态更新
【发布时间】:2022-02-25 06:05:50
【问题描述】:

每当有任何与组件相关的异步任务执行并且该组件卸载时,React 通常都会给出这个警告 -

Can't perform a React state update on an unmounted component This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

我在 Internet 上找到了一些解决方案,将 isMount 标志(通过将其与 useRef 或 useState 一起使用)设为 true,然后在组件卸载时将其更新为 false。但是,根据 React 站点使用 isMount 的正确解决方案是一种反模式吗?

https://reactjs.org/blog/2015/12/16/ismounted-antipattern.html

【问题讨论】:

  • 当您尝试将状态更改应用于不再存在的组件时,通常会发生此问题。

标签: reactjs warnings anti-patterns


【解决方案1】:

在 React 的未来版本中,您可能不需要修复此问题。因为 React 开发团队将在未来的版本中删除这个警告。主要原因是此警告有时可能是误报。

根据 Dan Abramov 的这个提交 https://github.com/facebook/react/pull/22114

但是在那个版本发布之前解决这个问题的解决方案是什么 -

  1. 使用 isMountState 反模式 - 如果有人在他的代码中检查 isMounted 以解决此问题,那么该人执行此检查已经为时已晚,因为此警告表明 React 执行了相同的检查并且它失败了。

  2. 如果此问题是由于异步调用引起的。然后一种可能的解决方案是在您的代码中使用 AbortController API。 AbortController API 有助于中止任何已经进行的 ajax 调用。很酷的东西。对吧?

更多细节可以在这里找到

Abort Controller1

因此,如果它是一个 fetch API,则可以像这样使用 AbortController API

useEffect(() => {
  const abortController = new AbortController()
  // creating an AbortController
  fetch(url, {
      signal: abortController.signal
    })
    // passing the signal to the query
    .then(data => {
      setState(data)
      // if everything went well, set the state
    })
    .catch(error => {
      if (error.name === 'AbortError') return
      // if the query has been aborted, do nothing
      throw error
    })

  return () => {
    abortController.abort()
    // stop the query by aborting on the AbortController on unmount
  }
}, [])

如果你使用的是 axios,那么好消息是 axios 还提供了对 AbortController API 的支持 -

const fetchData = async (params) => {
        setLoading(true);
        try {
            const result = await axios.request(params);
            // more code here 

        } catch (curError) {
            if (axios.isCancel(curError)) {
                return false;
            }
            // error handling code 
        }
        return null;
    };

    useEffect(() => {
        const cancelToken = axios.CancelToken;
        const source = cancelToken.source();

            fetchData({
                ...axiosParams,
                cancelToken: source.token
            });
        
        return () => {
            source.cancel("axios request cancelled");
        };
    }, []); 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-27
    • 2019-09-11
    • 2021-08-07
    • 2020-06-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多