2017-02-22 94 views
1

我有一個父組件,名爲UsersTable(它是其他組件的子項,並具有usersroles作爲其道具)。 getRoles()函數正在爲使用ajax請求的用戶獲取所有角色。結果返回到render()並存儲在allroles變量中。問題是因爲Ajax是異步的,我並不總是得到我需要的值在allroles變量。它有時爲空或者爲所有用戶返回相同的值。我想我應該按照說明使用componentDidMount和componentWillReceiveProps。但我無法弄清楚。另外,我認爲allroles應該是一個狀態,但這樣做會使代碼處於無限循環,並且瀏覽器會一直調用ajax請求!如何確保數據在渲染ReactJS組件之前已通過AJAX加載?

這裏是父組件代碼:

export const UsersTable = React.createClass({ 
    getRoles(){ 
     var oneRole = ""; 
     this.props.users.forEach(function(user){ 
      server.getUserRoles(user.id,   
       (results) => { 
        this.oneRole =results['hits']['hits'] 
        notifications.success("Get was successful "); 
       }, 
       () => { 
        notifications.danger("get failed "); 
       }); 
      }.bind(this)); 
     return this.oneRole; 
    }, 

    render() { 
     var rows = []; 
     var allroles = this.getRoles() 
     this.props.users.map(function(user) { 
      rows.push(<UserRow userID={user.id} 
           userEmail={user.email} 
           userRoles={allroles} 
           roles={this.props.roles} />); 
      }.bind(this)); 
     return (
      <table className="table"> 
       <thead> 
        <tr> 
         <th>Email Address</th> 
         <th>Role</th> 
         <th>Edit</th> 
        </tr> 
       </thead> 
       <tbody>{rows}</tbody> 
      </table> 
     ); 
    }  
}); 

這裏是子組件代碼:

export const UserRow = React.createClass({ 
    var showRoles = this.props.userRoles.map((role) => <div> {role.description || ''}</div>); 
    render(){ 
     return (
      <tr> 
       <td>{this.props.userEmail}</td> 
       <td>{showRoles}</td> 
      </tr> 
     ); 
    } 
}); 
+0

你不使用好AJAX asyncronous概念。 http://stackoverflow.com/questions/4559032/easy-to-understand-definition-of-asynchronous-event –

回答

0

你是說,你應該使用的生命週期方法是正確的。

作爲一般規則,如果您只需要在開始時填充一次數據,則使用componentDidMount

使用componentWillReceiveProps如果它必須收集更多數據(基於道具更改)。

作爲一個旁註,對於您的特定示例,您似乎通過循環多次調用後端。從問題中不可能分辨出來,但是如果你使用的是承諾庫,你可以將所有這些承諾推入一個數組中,然後執行一個Promise.all().then(/* update state */)

+0

我不知道該怎麼做。例如假設我有一個componentDidMount函數,在它的正文中我應該調用getRoles(),對不對?但那麼如何將用戶傳遞給它呢?另外,我不知道承諾:(是否有任何其他方式來解決這個問題?我應該更好的功能將它從渲染()到一個新的功能呢?我想我讀的地方,國家不應該在更新渲染()。也許這就是原因.... – petergil

+0

我把togther快​​速codepen。有什麼要求你用?愛可信庫? – Chris

0

首先要做的事情是把它放在一個沒有無限循環的狀態,您需要一個構造函數方法,您可以在其中調用super()方法,然後可以定義狀態。所以,你需要的東西是這樣的:

constructor() { 
    super(); 
    this.state = { 
     allroles: null 
    } 
} 

之後,當你正確地指出,你所需要的生命週期掛鉤:componentDidMount()

你需要第一個來填充你的狀態。所以調用它,應該是這個樣子:

componentDidMount() { 
    this.setState({allroles: this.getRoles()}) 
} 

現在,如果你需要獲取新的更新,你必須知道該更新是否會被觸發,用戶的互動的結果(例如,它們在添加新條目表)或基於時間的更新(例如,使用每隔一定時間調用this.getRole()的時間間隔)。無論哪種方式,您都需要再次使用this.setState({allroles: this.getRoles()})

在這種情況下,您不需要componentWillReceiveProps(),因爲此組件在不接收道具的情況下管理自己的狀態。如果你將會收到角色作爲道具,你將需要componentWillReceiveProps()

最後,回答爲什麼你有一個無限循環是因爲this.setState()觸發組件的重新渲染。這意味着,如果你在render()方法調用this.setState(),你會

  1. 渲染()
  2. 重新渲染觸發
  3. 渲染()
  4. 重新渲染觸發 ...

這就是爲什麼你不能在你的render()方法直接this.setState()打電話,而是把它無論是在一個事件或特定的生命週期掛鉤(即是CA的那些LLED之前渲染髮生或者被認爲是最初的渲染)