修改状态数组中的任何值时,ReactJS组件状态不会更新

时间:2019-01-09 04:48:06

标签: reactjs lodash react-state

在我的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中的componentDidUpdate()不会更新我的状态。

我还尝试了componentDidUpdate中的以下逻辑:

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

但这会进入inifinte循环,即使没有任何更改,也会增加API调用。

我该如何实现?

谢谢!

**需要等待该问题的解决方案。

更新:

从所有答案中,我想我应该用示例示例进行解释。因此,当我进行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 :(得分:0)

我想您在Lodash Docs中遇到语法错误,您需要在函数前添加下划线。

尝试执行以下操作:

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

另外,请检查两个数组是否唯一,并且比较是否在当前进行。那就是你的问题所在。

答案 1 :(得分:0)

 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();
   }
 }

答案 2 :(得分:0)

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;
  }

答案 3 :(得分:0)

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();
}