2015-03-31 14 views
9

Così ho questa componenteReagire arbitri non aggiornano tra rendere

var LineItemRowsWrapper = React.createClass({ 
    current_lineitem_count: 0, 

    getAjaxData: function(){ 
    var lineitem_data = []; 
    for(var i = 0; i < this.current_lineitem_count; i++){ 
     var data = this.refs['lineitem_'+i].getAjaxData(); 

     lineitem_data.push(data) 
    } 
    return lineitem_data; 
    }, 

    getLineitems: function(){ 
    var self = this; 

    var lineitem_components = []; 
    this.current_lineitem_count = 0; 
    if(this.props.shoot){ 
     var preview = this.props.preview; 

     var lineitems = this.props.shoot.get_lineitems(); 


     lineitem_components = lineitems.map(function (item, index) { 
      var ref_str = 'lineitem_'+self.current_lineitem_count; 
      self.current_lineitem_count++; 

      return (
      <LineItemRow item={item} key={index} ref={ref_str} preview={preview} onChange={self.props.onChange} /> 
     ) 
     }); 
     } 

    return lineitem_components; 
    }, 

    render: function() { 
    var lineitems = this.getLineitems(); 
    return (
     <div> 
     {lineitems} 
     </div> 
    ) 
    } 
}) 

i primi LineItems tempo sono resi gli arbitri funzionano come previsto. Ma se aggiungo un lineitem a this.props.shoot l'oggetto refs di questo componente non cambia.

Così, per esempio dire che ho avuto una serie di 3 LineItems

[i1,i2,i3] 

this.refs sarebbe

{lineitem_0:{}, lineitem_1:{}, lineitem_2:{}} 

e quando aggiorno il mio allineamento LineItem essere

[i1,i2,i3,i4] 

this.refs non cambia, sarà comunque

{lineitem_0:{}, lineitem_1:{}, lineitem_2:{}} 

perché l'oggetto ref non si aggiorna tra i rendering? I componenti LineItemRow si aggiornano correttamente quindi so che non è qualcosa di sbagliato su questo fronte. Qualsiasi intuizione sarebbe molto apprezzata!

____Edit____ (richiesto per aggiungere più codice per il contesto)

var DocumentContent = React.createClass({ 
    contextTypes: { 
    router: React.PropTypes.func.isRequired 
    }, 

    getParams: function(){ 
    return this.context.router.getCurrentParams() 
    }, 

    getInitialState: function() { 
    return { 
     shoot: ShootStore.get_shoot(this.getParams().shoot_id), 
    } 
    }, 

    componentWillMount: function() { 
    ShootStore.bind('change', this.onStoreUpdate); 
    }, 

    componentWillUnmount: function() { 
    ShootStore.unbind('change', this.onStoreUpdate); 
    }, 

    onStoreUpdate: function(){ 
    this.setState(this.getInitialState()); 
    }, 



    addLineItem: function() { 
     ShootActions.create_lineitem(this.state.shoot.id); 
    }, 


    update_shoot_timeout: null, 

    update_shoot:function(){ 
    var self = this; 
    window.clearTimeout(this.update_shoot_timeout) 
    this.update_shoot_timeout = window.setTimeout(function(){ 

     var lineitem_data = self.refs.lineitems.getAjaxData() 

     if(self.props.shoot){ 
      ShootActions.update_shoot(self.state.shoot.id, lineitem_data) 
     } 
    }, 500) 
    }, 


    render: function() { 

    var shoot = this.state.shoot; 
    return (
     <div className='document__content'> 
      <div className='row'> 


      <div className='document__expenses'> 
       <h3 className='lineitem__title'> Expenses </h3> 
       <LineItemRowsWrapper shoot={shoot} onChange={this.update_shoot} ref='lineitems'/> 

      </div> 
      <button onClick={this.addLineItem} className="btn-small btn-positive"> 
         + Add Expense 
        </button> 




     </div> 
    ); 
    } 
}) 
+1

Come e quando si aggiorna l'elenco LineItem? Che tipo di funzione è passata in this.pros.onChange? Hai un codice più pertinente? – magnudae

+1

Sto usando il flusso e quindi l'elenco dei lineitem viene aggiornato da un data_store e passato dal componente padre. Ho già controllato e tutto funziona correttamente. La funzione onChange passata salva i dati nel back-end e aggiorna l'archivio quando cambia un lineitem. La funzione onchange chiama getAjaxData(). metodo Questa è la parte più rilevante del codice, ma pubblicherò il mio altro codice. Tutto il resto funziona come dovrebbe. Sono abbastanza sicuro che questa è una cosa che reagisce.Perché l'elenco dei componenti {lineitems} che viene aggiornato è corretto e ha anche i refs corretti. –

+1

Ho letto qualcosa in più su refs sulla documentazione di Facebook. Sono diventato un po 'incerto se è possibile aggiungere dinamicamente più ref dopo il rendering iniziale. Non riesco a vedere alcun errore nel codice, quindi questa è la mia unica teoria. Continua a cercare, forse puoi trovare qualcosa [qui] (https://facebook.github.io/react/docs/more-about-refs.html). (se non l'hai già provato) – magnudae

risposta

0

Rimuovere tutti i vostri arbitri e l'iterazione per leggere i dati.

Il gestore onchange passato fino al componente LineItem deve essere chiamato e passato solo i dati che vengono modificati. (I singoli dati LineItem)

Questo viene quindi gestito dal componente con la gestione dello stato (DocumentContent).

Creare un'azione ShootActions.updateLineItem() che aggiorna l'elemento pubblicitario pertinente nello store, che quindi emette la modifica e restituisce tutto nuovamente.

+0

Penso che il wrapper sia un po 'ridondante dopo questo in realtà. – dannyshaw

4

Nella sezione "Attenzione" nella documentazione di reagire su arbitri https://facebook.github.io/react/docs/more-about-refs.html

"arbitri di accesso Mai all'interno del metodo render di un componente - o mentre qualsiasi render metodo è ancora in esecuzione in qualsiasi parte del stack di chiamate componente ".

Che è esattamente quello che stai facendo.

Invece si dovrebbe memorizzare lo stato sul componente in this.state o proprietà del componente nel this.props

Problemi correlati