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

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

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

Can't perform a React state update 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.

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

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 27.12.2018 17:26

@Morgan Мой API разработан на Django, а база данных - PostgreSQL

Rim J 28.12.2018 04:30
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
2
1 982
2

Ответы 2

Кажется, проблема связана с запросом 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 существует? Достаточно просто и элегантно.

Сообщите мне, если это не сработает!

С этим изменением моя таблица данных не работала, сортировка и поиск не работали. Затем я сделал три разных компонента для вкладок, после чего вызвал свой api в этих компонентах и ​​назвал эти файлы в компоненте Details. Теперь все работает нормально

Rim J 29.12.2018 05:17

Я действительно рада, что ты это понял! Извините, я больше не помог. :)

Morgan 29.12.2018 08:03

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

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

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

Другие вопросы по теме