在我的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;
答案 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();
}