我已经存储了 url
和一个 token
在state
在 Parent
零件。我正在传递 url
和一个 token
作为props
来自 parent Component
给 child Component
.但是,如果父级中有一些事件 Component
, setState()
被触发,结果,componentDidUpdate()
child 的Component
被执行。
作为componentDidUpdate()
导致无限循环(因为它触发了子组件内的 setState()),我已经放置了条件。但这并不能防止错误。
子组件即 DisplayRevenue
如下:
import React, { Component } from 'react';
import '../App.css';
import ListData from './listdata.js'
var axios = require('axios');
class DisplayRevenue extends Component {
constructor(props){
super(props);
this.state = { data:[], url:"" }
console.log(this.props.url);
}
componentWillMount() {
this.loadRevenue(this.props.url, this.props.token);
}
componentDidUpdate(){ //creates infinite loop
// console.log(this.props.url);
this.loadRevenue(this.props.url, this.props.token);
}
setData(data){
//if(this.state.url != this.props.url){
if(this.state.data != data.data){
console.log(data.data); //(1)
// console.log(this.state.url); //(2)
this.setState(data:data);
console.log(this.state.data); //(3)
// console.log(this.props.url); //(4)
} //(1) & (3) yields exactly same value so does (2) & (4)
}
loadRevenue(url,token){
axios({
method:'get',
url:url,
headers: {
Authorization: `Bearer ${token}`,
},
})
.then( (response) => {
// console.log(response.data);
this.setData(response.data);
})
.catch(function (error) {
console.log("Error in loading Revenue "+error);
});
}
render() {
return (
<ListData data={this.state.data}/>
);
}
};
export default DisplayRevenue;
父组件即 MonthToDate 如下:
import React, { Component } from 'react';
import '../App.css';
import DisplayRevenue from './displayRevenue'
var axios = require('axios');
class MonthToDate extends Component {
constructor(props){
super(props);
this.state = {
data:null,
url:"http://localhost:3000/api/monthtodate"
}
//console.log(this.props.location.state.token);
}
groupBySelector(event){
if ((event.target.value)==="invoice"){
this.setState({url:"http://localhost:3000/api/monthtodate"})
} else if ((event.target.value)==="customer") {
this.setState({url:"http://localhost:3000/api/monthtodate?group-by=customerNumber"})
} else if ((event.target.value)==="month") {
this.setState({url:"http://localhost:3000/api/invoices?group-by=month"})
} else {
this.setState({url:"http://localhost:3000/api/monthtodate"})
}
console.log(this.state.url);
}
render() {
return (
<div>
<select onChange={(event)=>this.groupBySelector(event)}>
<option value="invoice">GROUP BY INVOICE</option>
<option value="customer">GROUP BY CUSTOMER</option>
<option value="month">GROUP BY MONTH</option>
</select>
<DisplayRevenue url={this.state.url} token={this.props.location.state.token}/>
</div>
);
}
}
export default MonthToDate;
- 我错过了什么?
- 此外,在我收到
url
之后在子组件中,我想根据url
渲染不同的组件.例如<ListData />
组件只能处理一种类型的url
.如何在render()
中渲染另一个组件基于url
输入??
最佳答案
你在 componentDidUpdate
中调用了一个 ajax 调用,你在回调上设置了状态,这将触发另一个调用和更新,这将再次调用 ajax 请求,回调将再次设置状态等等上。
您在 setData
中的条件:
if(this.state.data != data.data)
将始终返回 true,因为对象是引用类型且无法比较,无论从 ajax 调用返回什么数据,它始终是一个不同的对象,并将在您的条件下返回 true
。
示例:
var obj1 = {a:1}
var obj2 = {a:1}
console.log(obj1 != obj2); // returns true
您可以做的是比较 primitives两个对象中的值。
例如:
if(this.state.data.id != data.id) // id could be a string or a number for example
编辑
我忘记提及的另一件事可能与您的问题没有直接关系,但应该强制执行,从不在 componentWillMount
或 constructor
中执行 ajax 请求这很重要,因为渲染函数将在您的 ajax 请求完成之前被调用。您可以在 DOCS 中阅读相关信息.
Ajax 请求应该在 componentDidMount
中调用 life cycle method相反。
编辑#2
另一件有用的事情是,在 MonthToDate
渲染函数中,您在每个渲染器上传递一个函数的新实例(这可能会导致性能下降)
<select onChange={(event)=>this.groupBySelector(event)}>
尝试将其更改为此(事件将自动传递给处理程序):
<select onChange={this.groupBySelector}>
您还需要在构造函数中绑定(bind)它:
constructor(props){
super(props);
this.state = {
data:null,
url:"http://localhost:3000/api/monthtodate"
}
//console.log(this.props.location.state.token);
this.groupBySelector = this.groupBySelector.bind(this); // binds this to the class
}
关于javascript - 为什么 componentDidUpdate() 会创建一个无限循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46195559/