2017-09-13 53 views
3

我已將和token存儲在stateParent組件中。我將urltoken作爲props從父Component傳遞給子Component。但是,如果母公司Component中有某個事件,則觸發setState(),結果子ComponentcomponentDidUpdate()被執行。
由於componentDidUpdate()導致無限循環(因爲它觸發子組件內的setState()),我已經放置條件。但是這並不能防止錯誤。
輔元件即DisplayRevenue如下:爲什麼componentDidUpdate()創建一個無限循環?

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的一種類型。如何根據url類型在render()內呈現另一個組件?
+0

爲什麼你在componentDidUpdate一個Axios公司的要求,將被執行的是愛可信要求對每一個渲染和進一步,因爲它確實的setState那張循環 –

+0

要設置狀態這使得愛可信的呼叫和設置狀態,並導致組件更新,並設置狀態,並導致更新,並設置狀態,並導致更新,並設置狀態,並導致更新,並設置狀態,並導致更新和設置狀態,導致更新和設置狀態,並導致更新,並設置狀態.... – bennygenel

+0

@ShubhamKhatri'setState()'裏面axios? axios正在調用'setData()',它在執行'setState()'之前檢查相等性' – noobie

回答

3

您調用componentDidUpdate Ajax調用,並設置上的回調,將觸發另一個調用和更新,這將再次調用Ajax請求和回調將再次等設置狀態的狀態。
您在setData條件:

if(this.state.data != data.data) 

因爲對象是引用類型和所不能比擬的,無論什麼數據從AJAX調用返回它永遠是一個不同的對象,並將返回true將始終返回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 Ajax請求或constructor因爲渲染功能將在您的ajax請求完成之前被調用。你可以在DOCS中閱讀。
應該在componentDidMountlife cycle method中調用Ajax請求。

編輯#2
另一件事,可以是有益的,在MonthToDate渲染功能,你在每個渲染傳遞函數的一個新實例(可會損害Reconciliation and diff algorithm):

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

嘗試將其更改爲這個(事件將自動傳遞給處理程序):

<select onChange={this.groupBySelector}> 

您還需要將它綁定在c onstructor:

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 
    } 
+0

好的。那麼請告訴我該怎麼辦? – noobie

+0

@noobie我已經編輯了答案 –

+0

我也嘗試過比較兩個字符串'if(this.state.url!= this.props.url)'(在代碼中註釋)它也不起作用。儘管在無限循環期間,當我記錄它們的o/p時,它們完全相同。 – noobie