ReactJS не мог обновить состояние при использовании вкладок

У меня есть компонент реакции с 3 вкладками, и каждая вкладка содержит таблицу данных, которая будет заполнена результатом вызова API на основе активной вкладки. Таким образом, каждый раз будет параметр, который я передаю с вызовом API и соответствующим образом отображаю данные.

Это отлично работает, я получаю данные, когда переключаюсь между вкладками, но когда я пытаюсь выполнить поиск в таблице данных, а затем нажимаю на другую вкладку, я получаю сообщение об ошибке:

Невозможно выполнить обновление состояния React для несмонтированного компонента. Это не работает, но указывает на утечку памяти в вашем приложении. Чтобы исправить, отмените все подписки и асинхронные задачи в методе componentWillUnmount.

Ниже мой пример кода:

компонент.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.

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


person Reema Parakh    schedule 27.12.2018    source источник
comment
Можете ли вы уточнить, что такое база данных и где находится код для нее?   -  person Morgan    schedule 27.12.2018
comment
@Morgan Мой API разработан в Django, а база данных - PostgreSQL.   -  person Reema Parakh    schedule 28.12.2018


Ответы (2)


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

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

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

person Garrett Motzner    schedule 29.12.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? Достаточно просто и элегантно.

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

person Morgan    schedule 29.12.2018
comment
С этим изменением моя таблица данных не работала, сортировка и поиск не работали. Затем я сделал три разных компонента для вкладок, и после этого я вызвал свой API в этих компонентах и ​​назвал эти файлы в Компоненте деталей. Теперь все работает нормально - person Reema Parakh; 29.12.2018
comment
Я очень рад, что ты это понял! Извините, я больше ничем не помог. :) - person Morgan; 29.12.2018