首页 > 解决方案 > 无法使用 componentDidMount 从 API 获取数据:无法在未安装的组件上调用 setState(或 forceUpdate)

问题描述

我对 React 比较陌生。我用它来构建一个非常简单的应用程序。我正在尝试添加一个小功能,但遇到以下错误消息。我还不太明白根本原因。

Can't call setState (or forceUpdate) 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 the componentWillUnmount method.

这就是我想要做的。我的应用程序有一个提供各种 API 的后端服务器,它返回 JSON。我将 React 用作​​调用这些 API 并呈现它们的前端/客户端。

我有一个名为 Parent 组件MyReport,用于componentDidMount调用 API 来获取一些数据。然后在 render 方法中,我将数据传递给另一个名为MyReportViewer. 该组件具有各种其他子组件,例如允许选择日期的日历、以表格格式显示数据的组件、将相同数据显示为图表的组件。

现在我正在尝试添加另一个名为的子组件MyReportSummary,它将与由MyReportViewer.

MyReportSummary需要调用另一个 API 来获取一些数据。这是它的样子:

import React, { Component } from 'react';

class MyReportSummary extends Component {

    constructor(props) {
        super(props);
        this.state = {
            projectInfo: null,
            isLoading: false,
            error: null
        };
    }

    componentDidMount() {
        this.setState({ isLoading: true });

        let projectInfoApi;

        projectInfoApi = '/api/projects/' + this.props.projectId;

        fetch(projectInfoApi)
            .then(response => {
                if (response.ok) {
                    return response.json();
                } else {
                    throw new Error('Encountered problem fetching project info')
                }
            })
            .then(data => this.setState({
                projectInfo: data
            }))
            .catch(fetchError => this.setState({
                isLoading: false,
                error: fetchError
            }));
    }

    componentWillUnmount() {
        // this.setState({
        //     projectInfo: null
        // });
    }

    render() {
        const { isLoading, error } = this.state;

        if (error) {
            return <p>{error.message}</p>
        }

        if (isLoading) {
            return <p>Loading...</p>
        }

        return (
            <div className="myReportSummary">
                 Summary of Project name: {projectInfo.name}                    
                 Number of events: {this.props.data.length}
            </div>
        );
  }
}

export default MyReportSummary;

我已经读过我需要用来componentWillUnmount重置所有内容,但我不确定我到底需要在这里重置什么以及为什么在这种情况下我需要这样做,因为我不认为我正在尝试更改组件在它已经加载或渲染之后。

标签: javascriptreactjs

解决方案


该警告表明您的组件在您有机会处理获取的响应之前已被卸载。

您可以在名为 eg 的状态之外保留组件上的属性,isMounted并将其设置为falseincomponentWillUnmount并检查是否是true您的 fetch 完成的时间:

例子

class MyReportSummary extends Component {
  mounted = true;
  state = {
    projectInfo: null,
    isLoading: true,
    error: null
  };

  componentDidMount() {
    fetch(`/api/projects/${this.props.projectId}`)
      .then(response => {
        if (response.ok) {
          return response.json();
        } else {
          throw new Error("Encountered problem fetching project info");
        }
      })
      .then(data => {
        if (this.mounted) {
          this.setState({
            projectInfo: data
          });
        }
      })
      .catch(fetchError => {
        if (this.mounted) {
          this.setState({
            isLoading: false,
            error: fetchError
          });
        }
      });
  }

  componentWillUnmount() {
    this.mounted = false;
  }

  render() {
    const { isLoading, error, projectInfo } = this.state;

    if (error) {
      return <p>{error.message}</p>;
    }

    if (isLoading) {
      return <p>Loading...</p>;
    }

    return (
      <div className="myReportSummary">
        Summary of Project name: {projectInfo.name}
        Number of events: {this.props.data.length}
      </div>
    );
  }
}

推荐阅读