为什么componentDidUpdate()创建一个无限循环?

我已经存储url了一个tokenin statein

Parent组件。我传递的urltokenprops从父Component到子Component。然而,如果在父母一些事件ComponentsetState()被触发,因此,componentDidUpdate()儿童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;

  • 我想念什么?
  • 另外,在收到urlin子组件之后,我想基于那个渲染另一个组件url。例如<ListData />component只能处理一种类型的url。如何render()根据url类型在其中渲染另一个组件?

回答:

您正在中调用ajax调用componentDidUpdate,并在回调上设置了状态,这将触发另一个调用并进行更新,这将再次调用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

您可以做的就是比较两个对象中的原始值。

例如:

if(this.state.data.id != data.id) // id could be a string or a number for example

我忘记提及的另一件事可能与您的问题没有直接关系,但应该强制执行,

在内部componentWillMount或之内进行Ajax请求constructor,因为在您的Ajax请求完成之前将调用render函数。您可以在DOCS中阅读有关它的信息。

应该在componentDidMount 生命周期方法中调用Ajax请求。

另一件事可能会有所帮助,在MonthToDate渲染函数中,您正在每个渲染器上传递函数的新实例(这可能会导致性能下降)

<select onChange={(event)=>this.groupBySelector(event)}>

尝试将其更改为此(事件将自动传递给处理程序):

 <select onChange={this.groupBySelector}>

您还需要将其绑定到构造函数中:

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

}

以上是 为什么componentDidUpdate()创建一个无限循环? 的全部内容, 来源链接: utcz.com/qa/416510.html

回到顶部