ReactJS не удалось обновить состояние при использовании с вкладками - PullRequest
0 голосов
/ 27 декабря 2018

У меня есть компонент реагирования с 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.

Так что может быть возможным решением для этого.

Ответы [ 2 ]

0 голосов
/ 29 декабря 2018

Похоже, проблема в том, что у вас есть модель данных, которая хранится в состоянии компонента, но этот компонент не задерживается слишком долго.Таким образом, у вас есть несколько вариантов:

  • Сохранение состояния в компоненте и отмена асинхронного запроса при размонтировании компонента.это можно сделать в axios, используя отмену токенов , которые вы создадите при создании и сработаете при размонтировании.Это также отменит запрос http, поэтому серверу на другой стороне не придется отвечать на него.Это может быть самым чистым вариантом, если вам нужно остановить выполнение любых запросов при переключении вкладок.
  • Просто игнорируйте предупреждение.Вам решать, важно это исправить или нет.Кажется, это не влияет на поведение.Ответ Моргана, по сути, делает это, и это вполне жизнеспособное решение, но оно побеждает цель предупреждения .
  • Удаляет состояние из компонента (и передает его как подпорки иликонтекст).Если состояние не сохраняется в компоненте, то обновление его после размонтирования компонента больше не является проблемой.Дополнительным преимуществом является то, что вам не нужно повторно выбирать состояние каждый раз, когда вы монтируете компонент, если вы этого не хотите.Вы можете сохранить состояние в родительском компоненте более высокого уровня, который не размонтируется и передать обработчик обновления, а также состояние этому компоненту, или вы можете использовать что-то вроде Redux или MobX для обработки состояния для вас.
  • Не отключайте компонент при переключении вкладок.Если вы сохраняете компонент визуализированным, но просто скрываете его с помощью html и css, то компонент остается подключенным.Есть и другие хитрые уловки, которые вы можете сделать, например, держать компонент смонтированным, но в «закадровом» фрагменте документа.Преимущество этого состоит в том, что он может ускорить рендеринг, но он может использовать больше памяти, а также является своего рода противодействующим паттерном.

Какой вариант вы выберете, зависит от того, чего вы хотите достичь.

0 голосов
/ 29 декабря 2018

Кажется, проблема связана с запросом POST, который вы отправляете в componentDidMount.

  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?Просто и достаточно элегантно.

Дайте мне знать, если это не сработает!

...