如何处理 React 的:无法在未安装的组件上执行 React 状态更新

问题描述 投票:0回答:2

我有一个包含 3 个图表(图形)的组件,使用 React.js 作为框架,

Highcharts
HighchartsReact
来创建图表。 为了将数据填充到这些图表中,我向服务器发出 3 个请求,为每个图表提供数据。 当组件安装时,它发出请求(使用 Axios),等待响应,将数据传递到图表,然后在 DOM 中显示/绘制。

应用程序的结构方式: Axios 文件:

  • utils(获取、发布、放置调用)
  • 拦截器

组件:

  • 应用程序.jsx
    • 根.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();
}, []);

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

javascript reactjs highcharts axios
2个回答
1
投票

我该如何处理这个问题?我应该:

  • 停止 url 更改的请求?
  • 组件卸载时停止请求?
  • 其他解决方案??

另一个选择是升级到 React 18 版本,该版本删除了此警告。它被删除的部分原因是它可能会产生误导:您的代码实际上不会造成内存泄漏。您获取一次数据,设置状态,然后返回。到那时,javascript 就可以清理闭包变量了。持久订阅可能会导致内存泄漏(例如,您忘记拆除的 Websocket),但您没有这样做。

如果您想在不更改反应版本的情况下消除警告,那么您应该添加一个清理功能来达到您的效果。您将保存一个变量,表明它已卸载,然后如果该变量已设置,则跳过设置状态。

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;
  };
}, []);

0
投票

此警告表明,即使发起调用的组件已卸载,某些异步代码/回调仍在运行。当组件卸载时,您应该清理这些“连接”,以免资源泄漏。

过去,建立了“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(); }; }, []);

© www.soinside.com 2019 - 2024. All rights reserved.