【问题标题】:ReactJS could not update state when used with TabsReactJS 与 Tabs 一起使用时无法更新状态
【发布时间】:2019-05-25 12:46:31
【问题描述】:

我有一个带有 3 个选项卡的反应组件,每个选项卡都包含一个数据表,该数据表将根据活动选项卡填充 API 调用结果。 所以每次都会有一个参数,我通过 API 调用传递并相应地显示数据。

这很好用,我在切换选项卡时获取数据,但是当我尝试从数据表中搜索然后单击另一个选项卡时,我收到错误 -

无法对未安装的组件执行 React 状态更新。这是 无操作,但它表明您的应用程序中存在内存泄漏。修理, 取消所有订阅和异步任务 componentWillUnmount 方法。

下面是我的示例代码:

component.jsx

import React, { Component } from "react";
import axios from "axios";

class Details extends Component {
  constructor() {
    super();
    this.state = {
      data: [],
      flag: 0
    };

  }

  componentDidMount() {
    const params = new FormData();
    params.append("status", "upcoming");
    axios.post("details/", params).then(res => {

      if (res.data.result === 1) {
        this.setState({ data: res.data.data, flag: 1 });
      }
    });
  }



  handleClick = event => {
    const params = new FormData();
    params.append("status", event.target.getAttribute("data-value"));
    axios.post("details/", params).then(res => {
      if (res.data.result === 1) {
        this.setState({ data: res.data.data, flag: 1 });
      }
    });
  };

  render() {
    return (
      <div className="col-md-9 col-sm-9 col-xs-12">
        <div className="right_panel">

          <h2>Listing</h2>

          <div className="responsive-tabs text-center ">
            <ul className="nav nav-tabs" role="tablist">
              <li role="presentation" className="active">
                <a
                  href="#Upcoming"
                  data-value="upcoming"
                  onClick={this.handleClick}
                  aria-controls="Upcoming"
                  role="tab"
                  data-toggle="tab"
                >
                  Upcoming
                </a>
              </li>
              <li role="presentation" className="">
                <a
                  href="#Current"
                  data-value="active"
                  onClick={this.handleClick}
                  aria-controls="Current"
                  role="tab"
                  data-toggle="tab"
                >
                  Current
                </a>
              </li>
              <li role="presentation" className="">
                <a
                  href="#past"
                  data-value="past"
                  onClick={this.handleClick}
                  aria-controls="past"
                  role="tab"
                  data-toggle="tab"
                >
                  Past
                </a>
              </li>
            </ul>
            <div
              id="tabs-content"
              className="tab-content panel-group table-responsive"
            >
              <div className="panel-heading" role="tab" id="heading2">
                <a
                  href="#Upcoming"
                  className="text-left collapsed textuppercase"
                  role="button"
                  data-toggle="collapse"
                  data-parent="tabs-content"
                  aria-expanded="true"
                  aria-controls="Upcoming"
                >
                  <i className="fas fa-list-ul" /> Upcoming
                  <i className="fas fa-chevron-down pull-right" />
                </a>
              </div>
              <div
                id="Upcoming"
                role="tabpanel"
                className="tab-pane active panel-collapse collapse in"
                aria-labelledby="heading2"
              >
                <table
                  id="first_Datatable"
                  className="display"
                  style={{ width: "100%" }}
                >
                  <thead>
                    <tr>
                      <th>#</th>
                      <th>Name</th>
                      <th>Open</th>
                      <th>Close</th>
                      <th>Listed</th>
                      <th>Price</th>
                      <th>Size</th>
                    </tr>
                  </thead>
                  {this.state.flag === 1 ? (
                    <tbody>
                      {this.state.data.map(d => (
                        <tr key={d.ipo_details_id}>
                          <td className="text-center">{d.ipo_details_id}</td>
                          <td>
                            <a href="#" title="">
                              {d.name}
                            </a>
                          </td>
                          <td>{d.open_date}</td>
                          <td>{d.close_date}</td>
                          <td>{d.size}</td>
                          <td>{d.listing}</td>
                          <td>{d.price}</td>
                        </tr>
                      ))}
                    </tbody>
                  ) : null}
                </table>
              </div>

              <div className="panel-heading" role="tab" id="heading3">
                <a
                  href="#Current"
                  className="collapsed text-left textuppercase"
                  role="button"
                  data-toggle="collapse"
                  data-parent="tabs-content"
                  aria-expanded="true"
                  aria-controls="Current"
                >
                  <i className="fas fa-list-ul" /> Current{" "}
                  <i className="fas fa-chevron-down pull-right" />
                </a>
              </div>

              <div
                id="Current"
                role="tabpanel"
                className="tab-pane panel-collapse collapse"
                aria-labelledby="heading3"
              >
                <table
                  id="second_Datatable"
                  className="display"
                  style={{ width: "100%" }}
                >
                  <thead>
                    <tr>
                      <th>#</th>
                      <th>Name</th>
                      <th>Open</th>
                      <th>Close</th>
                      <th>Listed</th>
                      <th>Price</th>
                      <th>Size</th>
                    </tr>
                  </thead>
                  {this.state.flag === 1 ? (
                    <tbody>
                      {this.state.data.map(d => (
                        <tr key={d.ipo_details_id}>
                          <td className="text-center">{d.ipo_details_id}</td>
                          <td>
                            <a href="#" title="">
                              {d.name}
                            </a>
                          </td>
                          <td>{d.open_date}</td>
                          <td>{d.close_date}</td>
                          <td>{d.size}</td>
                          <td>{d.listing}</td>
                          <td>{d.price}</td>
                        </tr>
                      ))}
                    </tbody>
                  ) : null}
                </table>
              </div>

              <div className="panel-heading" role="tab" id="heading3">
                <a
                  href="#past"
                  className="collapsed text-left textuppercase"
                  role="button"
                  data-toggle="collapse"
                  data-parent="tabs-content"
                  aria-expanded="true"
                  aria-controls="past"
                >
                  {" "}
                  <i className="fas fa-list-ul" /> Past{" "}
                  <i className="fas fa-chevron-down pull-right" />
                </a>
              </div>

              <div
                id="past"
                role="tabpanel"
                className="tab-pane panel-collapse collapse"
                aria-labelledby="heading3"
              >
                <table
                  id="third_Datatable"
                  className="display"
                  style={{ width: "100%" }}
                >
                  <thead>
                    <tr>
                      <th>#</th>
                      <th>Name</th>
                      <th>Open</th>
                      <th>Close</th>
                      <th>Listed</th>
                      <th>Price</th>
                      <th>Size</th>
                    </tr>
                  </thead>
                  {this.state.flag === 1 ? (
                    <tbody>
                      {this.state.data.map(d => (
                        <tr key={d.ipo_details_id}>
                          <td className="text-center">{d.ipo_details_id}</td>
                          <td>
                            <a href="#" title="">
                              {d.name}
                            </a>
                          </td>
                          <td>{d.open_date}</td>
                          <td>{d.close_date}</td>
                          <td>{d.size}</td>
                          <td>{d.listing}</td>
                          <td>{d.price}</td>
                        </tr>
                      ))}
                    </tbody>
                  ) : null}
                </table>
              </div>
            </div>
          </div>
        </div>
      </div>
    );
  }
}

export default Details;

我尝试使用 componentWillUnmount 进行更新,但没有解决。

我正在 index.html 中初始化数据表。

那么可能的解决方案是什么。

【问题讨论】:

  • 你能澄清一下数据库是什么以及它的代码在哪里吗?
  • @Morgan 我的API是用Django开发的,数据库是PostgreSQL

标签: reactjs axios react-dom react-state


【解决方案1】:

看起来这里的问题是您有一个数据模型,它以组件状态存储,但该组件并没有持续很长时间。所以你有几个选择:

  • 保持组件中的状态,并在组件卸载时取消异步请求。这可以在 axios 中使用cancel tokens 完成,您可以在构造时创建它并在卸载时触发。这也将取消 http 请求,因此另一端的服务器不必响应它。如果在切换选项卡时暂停任何正在进行的请求是您想要的行为,这可能是最干净的选项。
  • 忽略警告。这取决于你,如果解决这个问题很重要。它似乎不会影响行为。摩根的回答有效地做到了这一点,这是一个完全可行的解决方案,但它确实击败了purpose of the warning
  • 将状态移出组件(并将其作为道具或上下文传递)。如果状态没有存储在组件中,那么在组件卸载后更新它不再是问题。附带的好处是,如果您不想,每次挂载组件时都不必重新获取状态。您可以将状态保留在不会卸载的更高级别的父组件中,并将更新处理程序以及状态传递给该组件,或者您可以使用 ReduxMobX 之类的东西来为您处理状态。
  • 切换选项卡时不要卸载组件。如果您保持组件呈现,但只是用 html 和 css 隐藏它,那么组件将保持挂载。您还可以执行其他一些花哨的技巧,例如将组件安装在“屏幕外”文档片段中。这样做的好处是可以加快渲染速度,但会占用更多内存,而且还是一种反抗模式。

您选择哪个选项取决于您想要完成的任务。

【讨论】:

    【解决方案2】:

    问题似乎源于您在 componentDidMount 中发送的 POST 请求。

      componentDidMount() {
        const params = new FormData();
        params.append("status", "upcoming");
        axios.post("details/", params).then(res => {
    
          if (res.data.result === 1) {
            this.setState({ data: res.data.data, flag: 1 });
          }
        });
      }
    

    如果您在状态更新之前修改if 语句会怎样?

    if (res.data.result === 1 && this.state) {
    

    那样它只会在this.state 存在的情况下尝试更新状态?足够简单和优雅。

    如果这不起作用,请告诉我!

    【讨论】:

    • 通过此更改,我的数据表无法正常工作,排序和搜索也无法正常工作。然后我为选项卡制作了三个不同的组件,然后我在这些组件中调用了我的 api,并在详细信息组件中调用了这些文件。现在一切正常
    • 我真的很高兴你知道了!对不起,我没有更多的帮助。 :)
    猜你喜欢
    • 1970-01-01
    • 2020-09-20
    • 2019-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多