Состояние компонента ReactJS не обновляется при изменении любого значения в массиве состояний - PullRequest
0 голосов
/ 09 января 2019

В моем компоненте React я хочу, чтобы мое состояние автоматически обновлялось без перезагрузки страницы. Я использую метод lodash.iseqaual для сравнения изменения состояния, но это не обновление состояния.

Ниже мой компонент:

import React, { Component } from "react";
import { Link } from "react-router-dom";
import axios from "axios";
import $ from "jquery";
import isEqual from "lodash/isEqual";
$.DataTable = require("datatables.net");

class Active extends Component {
  state = {
    activeData: [],
    flag: 0,
    isLoading: true
  };

  componentDidMount() {
    this.getActiveData();
  }

  componentDidUpdate(prevProps, prevState) {
    if (!isEqual(prevState.activeData, this.state.activeData)) {
      this.getActiveData();
    }
  }

  getActiveData() {
    const params = new FormData();
    params.append("status", "active");
    axios.post("http://127.0.0.1:8000/details/", params).then(res => {
      if (res.data.result === 1) {
        this.setState({
          activeData: res.data.data,
          flag: 1,
          isLoading: false
        });
        if (!this.state.isLoading) {
          this.initTable();
        }
      } else if (res.data.result === 0) {
        this.setState({ isLoading: false });
        this.initTable();
      }
    });
  }

  initTable() {
    $("#Active_Datatable").DataTable();
  }

  render() {
    if (this.state.isLoading) {
      return (
        <img
          alt="loading"
          src="https://upload.wikimedia.org/wikipedia/commons/b/b1/Loading_icon.gif"
        />
      );
    }
    return (
      <React.Fragment>
        <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="Active_Datatable"
            className="display"
            style={{ width: "100%" }}
          >
            <thead>
              <tr>
                <th>#</th>
                <th>Name</th>
                <th>Open</th>
                <th>Close</th>
                <th>Price</th>
              </tr>
            </thead>
            {this.state.flag === 1 ? (
              <tbody>
                {this.state.activeData.map((ac, i) => (
                  <tr key={sc.id}>
                    <td className="text-center">{i + 1}</td>
                    <td>
                      <Link
                        to={{
                          pathname: `/${ac.name_slug}/`,
                          state: {
                            id: ac.id,
                            name: ac.name
                          }
                        }}
                      >
                        {sc.name}
                      </Link>
                    </td>
                    <td>{sc.open_date}</td>
                    <td>{sc.close_date}</td>
                    <td>
                      {Number(sc.price).toLocaleString("en-IN", {
                        currency: "INR"
                      })}
                    </td>
                  </tr>
                ))}
              </tbody>
            ) : null}
          </table>
        </div>
      </React.Fragment>
    );
  }
}

export default Active;

Метод lodash.isequal in componentDidUpdate() не обновляет мое состояние.

Я также попробовал приведенную ниже логику в componentDidUpdate:

componentDidUpdate(prevProps, prevState) {
    if (prevState.activeData !== this.state.activeData) {
      this.getActiveData();
    }
}

Но это идет в бесконечном цикле, и это увеличивает вызов API, даже после того, как нет изменений.

Как мне этого добиться?

Заранее спасибо!

** Нуждающиеся в ожидании решения этой проблемы.

UPDATE:

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

[
 {
   id: 1
   name: "ABC"
   close_date: "2019-01-11"
   open_date: "2019-01-08"
   price: "80"
 },
 {
   id: 2
   name: "XYZ"
   close_date: "2019-01-12"
   open_date: "2019-01-04"
   price: "80"
 }
]

Если, например, я обновлю поле имени с ABC до ABCD, возвращаемый результат будет:

[
 {
   id: 1
   name: "ABCD"
   close_date: "2019-01-11"
   open_date: "2019-01-08"
   price: "80"
 },
 {
   id: 2
   name: "XYZ"
   close_date: "2019-01-12"
   open_date: "2019-01-04"
   price: "80"
 }
]

И тогда значение имени в компоненте должно автоматически обновляться с ABC на ABCD, без перезагрузки страницы.

Этого не происходит ни с shouldComponentUpdate, ни с изменением моего синтаксиса lodash, как предложено.

Структура каталогов:

project
  |- public
  |- src
     -components
        -Header_Footer
          Header.jsx
          Footer.jsx
        -Home
          index.jsx
          -Details
             Active.jsx
             Upcoming.jsx
     App.js
     index.js    

Также я бы рассказал, как отображаются мои компоненты:

Details.jsx

import React, { Component } from "react";
import Active from "./Active";
import Upcoming from "./Upcoming";

class Details extends Component {

  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"
                  aria-controls="Upcoming"
                  role="tab"
                  data-toggle="tab"
                >
                  Upcoming
                </a>
              </li>
              <li role="presentation" className="">
                <a
                  href="#Current"
                  aria-controls="Current"
                  role="tab"
                  data-toggle="tab"
                >
                  Current
                </a>
              </li>

            </ul>
            <div
              id="tabs-content"
              className="tab-content panel-group table-responsive"
            >
              <Upcoming />
              <Active />
            </div>
          </div>
        </div>
      </div>
    );
  }
}

export default Details;

Home.js

import React, { Component } from "react";
import Sidebar from "./Sidebar";
import Details from "./details";

class Home extends Component {

  render() {
    return (
      <div className="container container_padding">
        <div className="row">
          <Sidebar />
          <Details />
        </div>
      </div>
    );
  }
}

export default Home;
* * App.js тысяча сорок-девять
import React, { Component } from "react";
import { Router, Route, Switch } from "react-router-dom";
import Header from "./components/Header_Footer/Header";
import Footer from "./components/Header_Footer/Footer";
import Home from "./components/Home";
import createBrowserHistory from "history/createBrowserHistory";
const history = createBrowserHistory();

class App extends Component {
  render() {
    return (
      <Router history={history}>
        <React.Fragment>
          <Header />
          <Switch>
            <Route exact path="/" component={Home} />
          </Switch>
          <Footer />
        </React.Fragment>
      </Router>
    );
  }
}

export default App;

Ответы [ 4 ]

0 голосов
/ 11 января 2019

getActiveData внутри componentDidUpdate будет вызываться только один раз, при первом возникновении componentDidUpdate, и никогда не будет вызываться снова, потому что prevState.activeData никогда не изменится.

вы можете попробовать другой способ, вызвать getActiveData() на componentDidUpdate и componentDidUpdate, использовать shouldComponentUpdate, чтобы решить, должен ли компонент обновляться или нет, здесь код

componentDidMount() {
    this.getActiveData();
}

shouldComponentUpdate(nextProps, nextState){
   return !isEqual(nextState.activeData, this.state.activeData)
}

componentDidUpdate() {
    this.getActiveData();
}
0 голосов
/ 09 января 2019
 you can also use the lodash package from this 
 https://www.npmjs.com/package/lodash

 $ npm i --save lodash        

 import isEqual from "lodash/isEqual";

 componentDidUpdate(prevProps, prevState) {
   if (!isEqual(prevState.activeData, this.state.activeData)) {
      this.getActiveData();
   }
 }
0 голосов
/ 09 января 2019
isEqual method is working Properly, You have need to change componentDidUpdate() method from getSnapshotBeforeUpdate() method because componentDidUpdate(prevProps, prevState) method execute after update the state so prevState having the same value which are having the this.state.activeData.

getSnapshotBeforeUpdate(prevProps, prevState) {
    if (!isEqual(prevState.activeData, this.state.activeData)) {
      this.getActiveData();
    }
    return null;
  }
0 голосов
/ 09 января 2019

Я полагаю, у вас есть некоторая синтаксическая ошибка согласно Документам Lodash , вам нужно добавить подчеркивание перед функцией.

Попробуйте сделать следующее:

if (!_.isEqual(prevState.activeData, this.state.activeData)) {
      this.getActiveData();
    }

Также, пожалуйста, проверьте, являются ли два массива уникальными или нет, и сравнение происходит в данный момент или нет. Вот где ваша проблема.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...