我已经存储url了一个tokenin statein Parent组件。我传递的url和token为props从父Component到子Component。然而,如果在父母一些事件Component,setState()被触发,因此,componentDidUpdate()儿童Component被执行。 由于componentDidUpdate()造成了无限循环 (因为它触发了子组件内部的setState()) ,所以我放置了条件。但这不能防止错误。 子组件即DisplayRevenue如下:
url
token
state
Parent
props
Component
setState()
componentDidUpdate()
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;
<ListData />
render()
您正在中调用ajax调用componentDidUpdate,并在回调上设置了状态,这将触发另一个调用并进行更新,这将再次调用ajax请求,而回调将再次设置状态,依此类推。 您的条件setData:
componentDidUpdate
setData
if(this.state.data != data.data)
因为对象是引用类型并且无法比较,所以将始终返回true,无论从ajax调用返回的数据是什么,它始终是不同的对象,并会true根据您的条件返回。例:
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请求。
componentWillMount
constructor
componentDidMount
编辑#2 另一件事可能会有所帮助,在MonthToDate渲染函数中,您正在每个渲染器上传递函数的新实例(这可能会导致性能下降)
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 }