当状态数组中的任何值被修改时,ReactJS 组件状态不会更新
Posted
技术标签:
【中文标题】当状态数组中的任何值被修改时,ReactJS 组件状态不会更新【英文标题】:ReactJS component state is not updating when any value in state array is modified 【发布时间】:2019-06-03 19:55:53 【问题描述】:在我的 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
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;
componentDidUpdate()
方法中的 lodash.isequal
没有更新我的状态。
我也尝试过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
我还要说明我的组件是如何渲染的:
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;
【问题讨论】:
不要使用componentDidUpdate
,如果使用最新版本,可以使用componentWillReceiveProps
或getderivedState
。
@Justcode componentWillReceiveProps
也没有这样做。我的反应版本是 16
请创建 stackblitz 链接以重现问题,并附上示例数据
@Justcode 我无法创建 stackblitz 链接,因为 dusring API 调用它说:net::ERR_SSL_PROTOCOL_ERROR
。我有 AWS EC2 服务器,我从哪里调用我的 API
【参考方案1】:
componentDidUpdate
中的getActiveData
只会被调用一次,在第一次 componentDidUpdate 发生时,它永远不会被再次调用,因为prevState.activeData
永远不会改变。
你可以试试其他方法,在componentDidUpdate
和componentDidUpdate
上触发getActiveData()
,使用shouldComponentUpdate
来决定组件是否应该更新,这里是代码
componentDidMount()
this.getActiveData();
shouldComponentUpdate(nextProps, nextState)
return !isEqual(nextState.activeData, this.state.activeData)
componentDidUpdate()
this.getActiveData();
【讨论】:
试过了,但现在this.getActiveData();
永远不会更新。我没有看到任何记录。它一直在加载。
@ReemaParakh 对不起,我忘记返回 true,只需更新答案,您可以再试一次吗
能否请您检查我更新的问题。我试图用示例来解释,因为shouldComponentUpdate()
没有更新值。【参考方案2】:
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;
【讨论】:
做到了。但是控制台说-index.js:1446 Warning: Active: getSnapshotBeforeUpdate() should be used with componentDidUpdate(). This component defines getSnapshotBeforeUpdate() only.
并且状态也没有更新。
getSnapshotBeforeUpdate() 方法是 react:16.3 的一部分,请检查反应版本。
这不起作用的任何原因? if (prevState.activeData !== this.state.activeData) this.getActiveData();
如果 activeData 在多个对象和数组中包含对象,则 !== 符号不能与多个对象和数组的值匹配,它将始终显示不同并且也匹配该引用财产。就像 activeData:id:2323, users[userId:"323", name:''"xyz", children: , userId:"323", name:''"xyz", children: ]
好的,那我将如何管理状态变化,即使lodash
isEqual 在这里也不起作用。【参考方案3】:
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();
【讨论】:
isEqual 方法工作正常,您需要从 getSnapshotBeforeUpdate() 方法更改 componentDidUpdate() 方法,因为 componentDidUpdate(prevProps, prevState) 方法在更新状态后执行,因此 prevState 具有相同的值this.state.activeData getSnapshotBeforeUpdate(prevProps, prevState) if (!isEqual(prevState.activeData, this.state.activeData)) this.getActiveData(); 返回空值; 使用此方法代替 componentDidUpdate(prevProps, prevState)【参考方案4】:我想你有一些 Lodash Docs 的语法错误,你需要在函数之前添加下划线。
尝试如下操作:
if (!_.isEqual(prevState.activeData, this.state.activeData))
this.getActiveData();
另外,请检查两个数组是否唯一,以及当前是否正在进行比较。这就是你的问题所在。
【讨论】:
我试过这个。但是componentDidUpdate()
方法没有被调用。我在做console.log("update"),它只打印2次。如果 DB 中的值发生更改并且状态已更新,则它不会捕获更新。它没有帮助。以上是关于当状态数组中的任何值被修改时,ReactJS 组件状态不会更新的主要内容,如果未能解决你的问题,请参考以下文章