【问题标题】:React - To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup functionReact - 修复,取消 useEffect 清理函数中的所有订阅和异步任务
【发布时间】:2021-03-24 22:03:05
【问题描述】:

我有以下代码

const Companies = () => {
  const [company, setCompany] = useState(plainCompanyObj);
  const [companiesData, setCompaniesData] = useState([]);
  
  useEffect(() => {
    Call<any, any>({
      url:
        _baseApiUrl +
        "-------api goes here --------",
      method: "GET",
      data: null,
      success: (companies) => {
        setCompaniesData(companies.companies);
      },
      authorization: sessionStorage.getItem("accessToken"),
    });
  }, []);

  return (
    //return JSX
  );
};

我收到以下错误:Warning: 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.

还只是为了澄清Call 标记是由axios 导入的方法,我用于URL 错误处理程序等。错误提示的问题在useEffect 部分。

【问题讨论】:

  • 你什么时候收到这个错误信息?
  • @NemanjaLazarevic 我的项目中只有一个 useEffect 所以应该是它
  • 您可以在渲染&lt;Companies /&gt; 组件的位置发布代码。也许在那里,你有一些逻辑会过早地卸载你的 &lt;Companies /&gt; 组件。
  • @NemanjaLazarevic 还有另一个名为 LayoutCompanies 的组件从 MatUI 返回一个 Box。 &lt;Box&gt; &lt;Companies /&gt; &lt;/Box&gt;
  • 显然,您不希望该组件卸载(错误提示)。要确认是这种情况,您可以在useEffect 的底部添加return () =&gt; {console.log("Component Unmounded")}。如果刷新后你看到这个日志,意味着你必须在组件树的某个地方搜索罪魁祸首。

标签: javascript jquery reactjs react-native use-effect


【解决方案1】:

您的问题是您在组件已卸载时调用setCompaniesData。 所以你可以尝试使用取消令牌来取消 axios 请求。 https://github.com/axios/axios#cancellation

const Companies = () => {
  const [company, setCompany] = useState(plainCompanyObj);
  const [companiesData, setCompaniesData] = useState([]);
  
  useEffect(() => {
    const cancelTokenSource = axios.CancelToken.source();

    Call<any, any>({
      url:
        _baseApiUrl +
        "-------api goes here --------",
      method: "GET",
      data: null,
      cancelToken: cancelTokenSource.token
      success: (companies) => {
        setCompaniesData(companies.companies);
      },
      authorization: sessionStorage.getItem("accessToken"),
    });
  }, []);

  return () => {
       cancelTokenSource.cancel();
  }
};

第二个选项是跟踪组件的挂载状态,只有在组件仍然挂载时才调用 setState。 在此处查看此视频:https://www.youtube.com/watch?v=_TleXX0mxaY&ab_channel=LeighHalliday

【讨论】:

    【解决方案2】:

    您遇到的问题是,您在向服务器创建请求的同时用户/您卸载(更改视图/重新渲染)正在等待来自服务器的数据的组件。

    取消 ajax 请求是一种很好的做法,它不仅仅是反应。

    Axios 使用取消令牌进行取消 - canceling

    根据我的经验,最好将整个 axios 包装到您自己的代码中。并在那里处理取消。 (类似于 api.get(/route); api.cancel(/route))

    希望对你有帮助

    【讨论】:

      【解决方案3】:

      这是一个带有异步任务取消的通用 json axios fetch 示例 (Live demo):

      import React, { useEffect, useState } from "react";
      import { CPromise, CanceledError } from "c-promise2";
      import cpAxios from "cp-axios";
      
      function MyComponent(props) {
        const [text, setText] = useState("fetching...");
      
        useEffect(() => {
          console.log("mount");
          const promise = CPromise.from(function* () {
            try {
              const response = yield cpAxios(props.url);
              setText(`Success: ${JSON.stringify(response.data)}`);
            } catch (err) {
              console.warn(err);
              CanceledError.rethrow(err); //passthrough
              // handle other errors than CanceledError
              setText(`Failed: ${err}`);
            }
          });
      
          return () => {
            console.log("unmount");
            promise.cancel(); // cancel async task
          };
        }, [props.url]);
      
        return <p>{text}</p>;
      }
      

      【讨论】:

        猜你喜欢
        • 2019-10-20
        • 2021-01-28
        • 2021-06-23
        • 2020-03-31
        • 1970-01-01
        • 1970-01-01
        • 2021-03-28
        • 1970-01-01
        • 2020-11-28
        相关资源
        最近更新 更多