2015-11-26 15 views
6

Sono di fronte a un problema di ciclo infinito e non riesco a vedere cosa lo stia attivando. Sembra che accada durante il rendering dei componenti.Componente di ciclo continuo su ReactJs

Ho tre componenti, organizzati in questo modo:

TimelineComponent 
    |--PostComponent 
     |--UserPopover 

TimelineComponenet:

React.createClass({ 
    mixins: [ 
     Reflux.listenTo(TimelineStore, 'onChange'), 
    ], 
    getInitialState: function() { 
     return { 
      posts: [],   
     } 
    }, 
    componentWillMount: function(){ 
     Actions.getPostsTimeline(); 
    }, 
    render: function(){ 
     return (
      <div className="timeline">     
       {this.renderPosts()} 
      </div> 
     ); 
    }, 
    renderPosts: function(){ 
     return this.state.posts.map(function(post){  
      return (
       <PostComponenet key={post.id} post={post} /> 
      ); 
     }); 
    }, 
    onChange: function(event, posts) { 
     this.setState({posts: posts}); 
    } 
}); 

PostComponent:

React.createClass({ 
    ... 
    render: function() { 
     return (
      ... 
      <UserPopover userId= {this.props.post.user_id}/> 
      ...   
     ); 
    } 
}); 

UserPopover:

module.exports = React.createClass({ 
    mixins: [ 
     Reflux.listenTo(UsersStore, 'onChange'), 
    ], 
    getInitialState: function() { 
     return { 
     user: null 
     }; 
    }, 
    componentWillMount: function(){ 
     Actions.getUser(this.props.userId); 
    }, 
    render: function() { 
     return (this.state.user? this.renderContent() : null); 
    }, 
    renderContent: function(){ 
     console.log(i++);  
     return (
     <div>   
      <img src={this.state.user.thumbnail} /> 
      <span>{this.state.user.name}</span> 
      <span>{this.state.user.last_name}</span> 
      ... 
     </div> 
    ); 
    }, 
    onChange: function() { 
     this.setState({ 
     user: UsersStore.findUser(this.props.userId)  
     }); 
    } 
}); 

Infine, c'è anche UsersStore **:

module.exports = Reflux.createStore({ 
    listenables: [Actions], 
    users: [], 
    getUser: function(userId){  
     return Api.get(url/userId) 
      .then(function(json){ 
       this.users.push(json); 
       this.triggerChange(); 
     }.bind(this)); 
    }, 
    findUser: function(userId) {    
     var user = _.findWhere(this.users, {'id': userId});  
     if(user){ 
      return user; 
     }else{ 
      this.getUser(userId); 
      return []; 
     } 
    }, 
    triggerChange: function() { 
     this.trigger('change', this.users); 
    } 
}); 

Tutto funziona correttamente se non il UserPopover componente.

Per ogni PostComponent sta rendendo uno UserPopOver che recuperare i dati nel ciclo willMount.

Il fatto è che, se ho notato questa riga di codice console.log(i++); nel componente UserPopover, che incrementi più e più volte

... 
3820 
3821 
3822 
3823 
3824 
3825 
... 

clearl un loop infinito, ma io davvero non so dove viene da. Se qualcuno potrebbe darmi un suggerimento, sarò molto riconoscente.

PS: ho già provato questo approccio nel UsersStore ma poi tutto il PostComponent avere lo stesso "utente":

... 
getUser: function(userId){  
    return Api.get(url/userId) 
     .then(function(json){ 
      this.user = json; 
      this.triggerChange(); 
    }.bind(this)); 
}, 
triggerChange: function() { 
    this.trigger('change', this.user); 
} 
... 

E nel UserPopover

... 
onChange: function(event, user) { 
    this.setState({ 
     user: user  
    }); 
} 
... 
+1

Grazie mille @ForceMagic per la tua recensione, ora è praticamente chiaro! – Yonirt

+1

Sono contento che ti piaccia! Ho davvero cercato di mantenere l'essenza mentre riorganizzavo alcune idee! :) – ForceMagic

risposta

2

Poiché i tuoi post sono fetch asincroni, credo che quando il componente UserPopover esegue il componente componentWillMount, props.userId non è definito, quindi si chiama UsersStore.findUser (this.props.userId), in UserStore, getUser viene chiamato perché non riesce a trovare l'utente nella memoria locale.

NOTA che ogni volta che aJax del getUser è terminato, si attiva.Quindi il componente UserPopover esegue la funzione onChange e chiama nuovamente UsersStore.findUser. Questo è un ciclo infinito.

Aggiungi un console.log (this.props.userId) nel componenteWillMount di UserPopover per scoprire se è come quello che ho detto sopra. In realtà non ne sono sicuro al 100%.

Questo è un problema che tutte le istanze di UserPopover condividono lo stesso UserStore, penso che dovremmo ripensare la struttura di questi componenti e negozi. Ma non ho ancora pensato il modo migliore.

1

Puoi farlo in questo modo:

TimelineComponent 
    |--PostComponent 
    |--UserPopover 

UserPopover basta ascoltare le modifiche e aggiornarsi.

UserPopover è in attesa di modifica nello store, che contiene i dati dell'utente in popover e gli aggiornamenti delle modifiche. Puoi anche inviare le coordinate dove renderizzare. Non è necessario creare Popover per ogni post.