2014-05-06 3 views
10

Sto tentando di creare/prototipare un widget con un filtro di ricerca e due pannelli con una relazione valore-chiave/padre-figlio. Il pannello di destra contiene categorie, il pannello di sinistra contiene interessi associati a una singola categoria. Le righe di categoria sono selezionabili per mostrare le caselle di controllo degli interessi associati. Non sono arrivato al punto di cercare di capire come aggiornare l'invio del modulo con le checkbox, prima devo capire di più sul modo corretto di rendere il flusso di dati.Come gestire gli eventi click sui componenti figlio in React.js, esiste un "modo" React?

Questa è la mia prima incursione in React e so che React incoraggia il flusso di dati a senso unico. Sento che sto aggiornando il pannello degli interessi in modo errato usando jQuery per gestire gli eventi. Mi piacerebbe sapere alcuni modi alternativi per aggiornare il pannello degli interessi.

Da quello che ho letto, per aggiornare i componenti parent (credo sia indicato come proprietario nei documenti di React) è necessario definire i callback sui componenti figlio/proprietario. Apprezzerei una spiegazione di questo e anche se sto usando in modo errato interessi nello stato contro oggetti di scena. Stavo tentando di avere solo il filtro di ricerca & le caselle di controllo come parte dello stato del widget, perché ho letto che i dati filtrabili dovrebbero appartenere agli oggetti di scena.

AGGIORNAMENTO: ho modificato gli interessi da inizializzare in getDefaultProps, quindi ora li sto usando come oggetti di scena. Penso che questo sia più il modo React, sono corretto? Ho anche cambiato il modo in cui gli interessi vengono aggiornati cambiando la funzione handleCategoryRowClick. Penso che sto facendo le cose più in questo modo, ma mi piacerebbe comunque avere qualche consiglio che chiunque abbia più esperienza con React potrebbe dare, grazie.

Qualsiasi aiuto sarebbe molto apprezzato!

/** @jsx React.DOM */ 

var InterestRow = React.createClass({ 
    render: function() { 
     return (
      <div> 
       <label>{this.props.interest.name}</label> 
       <input type="checkbox" ref={this.props.key} value={this.props.key} /> 
      </div> 
     ) 
    } 
}); 

var InterestPanel = React.createClass({ 
    var interestPanel = this; 
    var rows = []; 

    render: function() { 
     var rows = []; 
     var i = 0; 

     _(this.props.interests).each(function (interest) { 
      rows.push(<InterestRow interest={interest} key={interest.value} />); 
     }); 

     return (
      <form>{rows}</form> 
     ) 
    } 
}); 

var CategoryRow = React.createClass({ 
    render: function() { 
     return (
      <li onClick={this.props.handleClick.bind(null, this.props.interests)}>{this.props.category}</li> 
     ) 
    } 
}); 

var CategoriesPanel = React.createClass({ 
render: function() { 
    var categoriesPanel = this; 
    var rows = []; 
    var categories = []; 
    var interests = []; 
    var interestSet = []; 
    var missedSet = []; 
    var lastCategory = null; 
    var category; 
    var interest; 
    var i = 0; 

    _.each(categoriesPanel.props.data, function (datum) { 
     name = datum.name; 
     value = datum.targeting_value; 
     category = name.split('/')[0]; 
     interest = {name: name.split('/')[1], value: value} 

     if (_.contains(interest.name.toLowerCase(), categoriesPanel.props.searchText.toLowerCase())) { 
      if (category !== lastCategory) { 
       if (interestSet.length > 0) { 
        interests.push(interestSet.concat(missedSet)); 
       } 

       lastCategory = category; 
       categories.push(category); 
       interestSet = []; 
       interestSet.push(interest); 
       missedSet = []; 
      } else { 
       if (!_.contains(categories, category)) { 
        categories.push(category); 
        interestSet.push(interest); 
       } else { 
        interestSet.push(interest); 
       } 
      } 
     } else { 
      if (category !== lastCategory) { 
       if (interestSet.length > 0) { 
        interests.push(interestSet.concat(missedSet)); 
       } 

       lastCategory = category; 
       interestSet = []; 
       missedSet = []; 
       missedSet.push(interest); 
      } else { 
       missedSet.push(interest); 
      } 
     } 
    }); 

    if (interestSet.length > 0) { 
     interests.push(interestSet.concat(missedSet)); 
    } 

    var interestsObject = _.zipObject(categories, interests); 

    _.each(interestsObject, function (interestSet, category) { 
     i++; 
     rows.push(<CategoryRow category={category} key={i} interests={interestSet} handleClick={categoriesPanel.props.handleClick} />) 
    }); 

    return (
     <div> 
      <ul>{rows}</ul> 
     </div> 
    ) 
} 
}); 

var SearchBar = React.createClass({ 
    handleChange: function() { 
     this.props.onUserInput(
      this.refs.searchTextInput.getDOMNode().value 
     ) 
    }, 
    render: function() { 
     return (
      <form onSubmit={this.handleSubmit}> 
       <input 
        type="text" 
        placeholder="Search Interests..." 
        value={this.props.searchText} 
        ref="searchTextInput" 
        onChange={this.handleChange} 
       /> 
      </form> 
     ); 
    } 
}); 

var InterestsTable = React.createClass({ 
loadDataFromTwitter: function() { 
    $.ajax({ 
     url: this.props.url, 
     dataType: 'json', 
     success: function(data) { 
      this.setProps({data: data}); 
     }.bind(this) 
    }); 
}, 
getInitialState: function() { 
    return { 
     searchText: '' 
    } 
}, 
getDefaultProps: function() { 
    return { 
     data: [], 
     interests: [] 
    } 
}, 
componentWillMount: function() { 
    this.loadDataFromTwitter(); 
}, 
handleUserInput: function(searchText) { 
    this.setState({ 
     searchText: searchText 
    }); 
}, 
handleCategoryRowClick: function(interests) { 
    this.setProps({ 
     interests: interests 
    }); 
}, 
render: function() { 
    return (
     <div> 
      <SearchBar 
       searchText={this.state.searchText} 
       onUserInput={this.handleUserInput} 
      /> 
      <CategoriesPanel 
       data={this.props.data} 
       searchText={this.state.searchText} 
       handleClick={this.handleCategoryRowClick} 
      /> 
      <InterestsPanel 
       interests={this.props.interests} 
       searchText={this.state.searchText} 
      /> 
     </div> 
    ); 
} 
}); 

React.renderComponent(
    <InterestsTable url="/api/interests" />, 
    document.getElementById('content') 
); 

risposta

9
  • V'è una certa persistente jQuery che può essere rimosso:
componentDidMount: function() { 
     $(document).on("handleCategoryRowClick", this.handleCategoryRowClick); 
    }, 
  • Trattare props immutabile come spesso possibile e Reagire vita metodi del ciclo di funzioneranno come previsto. In questo caso, interests deve essere state anziché props poiché il componente InterestsTable possiede e lo modifica; non è passato dal genitore del componente:
getInitialState: function() { 
     return { 
     interests: [], 
     searchText: "" 
     }; 
    }, 
    handleCategoryRowClick: function(e, interests) { 
     this.setState({ 
     interests: interests 
     }); 
    }, 
+0

Ho dimenticato di rimuovere la funzione di jQuery, ma il mio codice non ha più lo ... Dalla documentazione Reagire [qui] (http: //facebook.github .io/react/docs/thinking-in-react.html # step-4-identify-where-your-state-should-live) sembra incoraggiare l'uso di oggetti di scena per qualsiasi dato che può essere calcolato tramite altri stati o oggetti di scena. C'è un vantaggio nell'usare lo stato contro gli oggetti di scena? Il modo in cui attualmente lo ha impostato come oggetti di scena e la funzionalità sta funzionando. – evkline

+0

Ho aggiornato il mio codice, ssorallen ... Ti sembra "React-ish"? Inoltre, attualmente il filtro di ricerca aggiorna gli input della casella di controllo presenti sul DOM. Se una casella di controllo è selezionata e il filtro di ricerca aggiorna il DOM, come posso memorizzare il valore della casella di controllo selezionata in React? Dovrei usare jQuery per afferrare e archiviare i dati sul client prima di inviarlo al server? – evkline

+0

P.S. So che il codice CategoriesPanel ha bisogno di qualche refactoring, ho intenzione di refactoring voleva solo ottenere tutto lavorando per primo. Grazie ancora per l'aiuto. – evkline