4

在我的 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.isequalincomponentDidUpdate()方法没有更新我的状态。

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

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

但这会进入无限循环,即使在没有变化之后也会增加 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    

另外我会告诉我的组件是如何呈现的:

详细信息.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;

主页.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;

应用程序.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

4 回答 4

0

我想你有一些Lodash Docs的语法错误,你需要在函数之前添加下划线。

尝试执行以下操作:

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

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

于 2019-01-09T05:51:14.817 回答
0

getActiveDatainsidecomponentDidUpdate只会被调用一次,在第一次发生 componentDidUpdate 时,并且永远不会再次调用,因为它prevState.activeData永远不会改变。

您可以尝试另一种方式,触发and ,用于getActiveData()决定该组件是否应该更新,这里是代码componentDidUpdatecomponentDidUpdateshouldComponentUpdate

componentDidMount() {
    this.getActiveData();
}

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

componentDidUpdate() {
    this.getActiveData();
}
于 2019-01-11T04:35:00.383 回答
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;
  }
于 2019-01-09T08:37:49.357 回答
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();
   }
 }
于 2019-01-09T06:28:10.753 回答