[英]Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate
There's already some people asking this question but they are almost caused by the same reason (fire the callback in situ eg <div onClick={this.handleClick()}></div>
).已经有人问了这个问题,但他们几乎是由相同的原因引起的(原地触发回调,例如
<div onClick={this.handleClick()}></div>
)。 However this doesn't happen to me but I got the same error.然而,这并没有发生在我身上,但我得到了同样的错误。
PS Some util functions are defined behind the scene. PS 一些 util 函数是在幕后定义的。
// Parent
export default class SearchArea extends React.Component {
constructor(props) {
super(props);
this.state = {
data: {
update: '',
confirmed: '',
recovered: '',
deaths: ''
},
showDashboard: false
}
this.setCountryData = this.setCountryData.bind(this);
this.showDashboard = this.showDashboard.bind(this);
}
setCountryData(data) {
console.log(data);
this.setState({
data: {
update: data.lastUpdate,
confirmed: data.confirmed,
recovered: data.recovered,
deaths: data.deaths
}
});
}
showDashboard(toggle) {
this.setState({ showDashboard: toggle })
}
render() {
return (
<div>
<Dropdown onSetCountryData={this.setCountryData} onShowDashboard={this.showDashboard} />
<Dashboard data={this.state.data} visible={this.state.showDashboard} />
</div>
)
}
}
// Sibling1
class Dropdown extends React.Component {
constructor(props) {
super(props);
this.state = {
countries: [],
currentCountry: ''
};
this.handleClick = this.handleClick.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleClick() {
const showCountryData = Fetch(newFetchCountry).showJSONData;
showCountryData().then(res => {
const data = res[0];
this.passCountryData(data);
})
this.passToggleDashboard(true);
}
handleChange(e) {
this.setState({ currentCountry: e.target.value, });
this.passToggleDashboard(false);
}
passCountryData(data) {
this.props.onSetCountryData(data);
}
passToggleDashboard(toggle) {
this.props.onShowDashboard(toggle);
}
componentDidMount() {
let timer = setTimeout(() => {
const showCountryList = Fetch(fetchCountryList).showJSONData;
showCountryList().then(res => {
const data = res.map(country => country);
this.setState({ countries: data })
});
clearTimeout(timer);
}, 2000)
}
render() {
return (
<section className="dropdown-area">
<div className="dropdown">
<label htmlFor="country">Select country:</label>
<input list="countries" name="country" id="country" onChange={this.handleChange} />
<datalist id="countries" required>
{this.state.countries.length ?
this.state.countries.map(country => <option key={country.name}>{country.name}</option>) :
<option disabled>Loading</option>}
</datalist>
</div>
<button className="comp" onClick={this.handleClick}>Search</button>
</section>
)
}
}
// Sibling2
class Dashboard extends React.Component {
constructor(props) {
super(props);
this.state = {
data: {
update: '',
confirmed: '',
recovered: '',
deaths: ''
}
};
}
componentDidMount() {
if (!('data' in this.props)) {
const showWorldData = Fetch(fetchWorld).showJSONData;
showWorldData().then(res => {
const data = res[0];
this.setState({
data: {
update: data.lastUpdate,
confirmed: data.confirmed,
recovered: data.recovered,
deaths: data.deaths
}
});
});
}
}
componentDidUpdate() { // Error here!!!
if ('data' in this.props) {
const data = this.props.data;
this.setState({
data: {
update: data.lastUpdate,
confirmed: data.confirmed,
recovered: data.recovered,
deaths: data.deaths
}
});
}
}
render() {
const visibility = {
visibility: 'visible' in this.props && !this.props.visible ? 'hidden' : 'visible'
};
return (
<section className="dashboard-area" style={visibility}>
<span>Last Update: {this.state.data.update || 'Loading...'}</span>
<div className="dashboards">
<DashboardItem num={this.state.data.confirmed} type="Confirmed" />
<DashboardItem num={this.state.data.recovered} type="Recovered" />
<DashboardItem num={this.state.data.deaths} type="Deaths" />
</div>
</section>
)
}
}
class DashboardItem extends React.Component {
render() {
return (
<div className="dashboard">{this.props.type}: <br /><span>{this.props.num || 'Loading...'}</span></div>
)
}
}
Error is in the componentDidMount()
in the Dashboard
component.错误出现在
Dashboard
组件中的componentDidMount()
中。 I can't find where I fired the re-render infinitely.我找不到无限触发重新渲染的位置。
The setState method is repeatedly updating the component because every time the 'data' in this.props
equals to true
you're calling setState
and calling setState will by default update the component and componentDidUpdate
will check again if 'data' in this.props
equals to true
and so setState 方法会重复更新组件,因为每次
'data' in this.props
等于true
时,您都会调用setState
并且调用 setState 默认会更新组件,并且componentDidUpdate
将再次检查'data' in this.props
等于true
等
You should make strict conditions for if
statement您应该为
if
语句制定严格的条件
try this尝试这个
componentDidUpdate(prevProps, prevState) {
if ('data' in this.props && this.props.data !== prevProps.data) {
const data = this.props.data;
this.setState({
data: {
update: data.lastUpdate,
confirmed: data.confirmed,
recovered: data.recovered,
deaths: data.deaths
}
});
}
}
Your issue stems from derived state: state which is made dependent on props and is an anti-pattern in react.您的问题源于派生的 state: state 它依赖于道具并且是反应中的反模式。
This will tell you more about it:这将告诉你更多关于它的信息:
https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html
There are some work arounds, but its recommended you instead restructure your data flow.有一些变通方法,但建议您改用重组数据流。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.