axios 如何使用React:无法在未挂载的组件上执行React状态更新

uinbv5nw  于 12个月前  发布在  iOS
关注(0)|答案(2)|浏览(143)

我有一个组件,有3个图表(图),使用React.js作为框架,HighchartsHighchartsReact来创建图表。为了将数据填充到这些图表中,我向服务器发出3个请求,为每个图表提供数据。当组件挂载时,它发出请求(使用Axios),等待响应,将数据传递到图表,然后在DOM中显示/绘制。
应用程序的结构方式:Axios文件:

  • utils(get,post,put calls)
  • 拦截器

组成部分:

  • App.jsx
  • Root.jsx
  • Charts.jsx
  • 其他页面.jsx

jsx:图表组件和其他页面将在此组件中显示)。它有一个导航栏,例如,当您单击导航栏中的图表图标时,它将重定向到图表页面。导航栏总是在那里。使用react-router-dom处理重定向。
问题是:当请求正在进行时,如果我访问另一个页面(相同的应用程序),并且组件卸载,我会得到错误:警告:无法在未挂载的组件上执行React状态更新。这是一个空操作,但它表明应用程序中存在内存泄漏。要修复,请取消useEffect清理函数中的所有订阅和异步任务。
我该怎么办?我是否应该:

  • 是否停止URL更改请求?
  • 卸载组件时是否停止请求?
  • 其他解决方案??

我尝试了abortController,但无法使其工作。老实说,我甚至不知道在我的情况下使用它是否有意义。

// axios utils
export const apiGetCall = (url) => axiosInstance.get(url);

// One of the function to get data from server and pass to chart

useEffect(() => {
  const fetchData = async () => {
    try {
      const response = await apiGetCall("/departments");
      const departmentsData = response.data.departments;

      // Update the state with the fetched department data
      setDepartmentData(departmentsData);

      // Move the contents of pieChartOptions to the useState hook
      setPieChartOptions({
        // Department data
      });
    } catch (err) {
        console.log(err);
    }
  };

  fetchDepartmentData();
}, []);

我只是插入了相关的代码。图表显示等。工作正常我只是需要帮助处理错误。

gz5pxeao

gz5pxeao1#

我该怎么办?我是否应该:

  • 是否停止URL更改请求?
  • 卸载组件时是否停止请求?
  • 其他解决方案??

另一个选择是升级到react 18版本,该版本删除了此警告。它被删除了,部分原因是它可能会误导:你的代码实际上并没有内存泄漏。您可以获取一次数据,设置状态,然后返回。在这一点上,JavaScript可以清理闭包变量。持久订阅可能会导致内存泄漏(例如,您忘记拆除的WebSocket),但您没有这样做。
如果你想在不改变react版本的情况下消除警告,那么你应该在你的效果中添加一个清理函数。您将保存一个变量,指示它已卸载,然后如果该变量已设置,则跳过设置状态。

useEffect(() => {
  let cancelled = false;
  const fetchData = async () => {
    try {
      const response = await apiGetCall("/departments");
      if (cancelled) {
        return;
      }
      const departmentsData = response.data.departments;

      // Update the state with the fetched departmentData
      setDepartmentData(departmentsData);

      // Move the contents of pieChartOptions to the useState hook
      setPieChartOptions({
        // Department data
      });
    } catch (err) {
      console.log(err);
    }
  };

  fetchData();

  return () => {
    cancelled = true;
  };
}, []);
p3rjfoxz

p3rjfoxz2#

此警告表示某些异步代码/回调仍在运行,即使在启动调用的组件已卸载之后也是如此。当组件卸载时,您应该清理这些“连接”,这样就不会有资源泄漏。
在过去,“isMounted”检查被建立为一种检查组件是否仍然被挂载并有条件地 * 不**尝试状态更新的方法,但这已经不再推荐,并被认为是React反模式。
在这里,您应该使用中止令牌来取消卸载组件时的任何动态网络请求。(* 模式与旧的“isMounted”逻辑非常相似 *)。
有关详细信息,请参阅AbortController和Axios Cancellation文档。
示例实施方式:

// axios utils
// (0) Update apiGetCall function to consume an options object arg
export const apiGetCall = (url, options) => axiosInstance.get(url, options);
// One of the function to get data from server and pass to chart
useEffect(() => {
  // (1) Create an abort controller
  const controller = new AbortController();

  const fetchData = async () => {
    try {
      const { data } = await apiGetCall(
        "/departments",
        {
          // (2) Pass controller signal in options to GET call
          signal: controller.signal
        }
      );

      const departmentsData = data.departments;

      // Update the state with the fetched department data
      setDepartmentData(departmentsData);

      // Move the contents of pieChartOptions to the useState hook
      setPieChartOptions({
        // Department data
      });
    } catch (err) {
      // (4) Aborted request Promise rejection, cancel error
      console.log(err);
    }
  };

  fetchData();

  return () => {
    // (3) Abort in-flight request on component unmount
    controller.abort();
  };
}, []);

相关问题