2015-06-15 3 views
13

मुझे एक क्लिक करने योग्य सूची घटक की शुरुआत मिली है जो एक चुनिंदा तत्व ड्राइव करने के लिए काम करेगा। जैसा कि आप ListItem के onClick से नीचे देख सकते हैं, मैं माता-पिता (SelectableList, और घटक) में एक बच्चे तत्व (ListItem) की स्थिति उत्तीर्ण कर रहा हूं। यह ठीक काम कर रहा है। हालांकि, मैं क्या करना चाहूंगा भाई घटकों (अन्य ListItems) की स्थिति को बदलना है ताकि जब मैं सूची में से किसी एक पर क्लिक किया जाता है तो मैं अपने चुने हुए राज्यों को टॉगल कर सकता हूं।मैं प्रतिक्रिया में आसानी से भाई घटकों की स्थिति कैसे निर्धारित करूं?

पल में, मैं बस तत्वों हड़पने और जब यह क्लिक ListItem के सूचकांक से मेल नहीं खाता चयनित करने के लिए वर्ग बदलने के लिए document.querySelectorAll('ul.cs-select li) उपयोग कर रहा हूँ। यह काम करता है - एक हद तक। हालांकि, कुछ क्लिक के बाद, घटक की स्थिति को प्रतिक्रिया द्वारा अपडेट नहीं किया गया है (केवल क्लाइंट साइड जेएस द्वारा), और चीजें तोड़ने लगती हैं। मैं क्या करना चाहता हूं भाई सूची वस्तुओं के this.state.isSelected को बदलें, और चयन योग्य सूची घटक को रीफ्रेश करने के लिए इस स्थिति का उपयोग करें। क्या कोई नीचे दिए गए कार्यों के लिए बेहतर विकल्प प्रदान कर सकता है?

var React = require('react'); 
var SelectBox = require('./select-box'); 

var ListItem = React.createClass({ 
    getInitialState: function() { 
     return { 
      isSelected: false 
     }; 
    }, 

    toggleSelected: function() { 
     if (this.state.isSelected == true) { 
      this.setState({ 
       isSelected: false 
      }) 
     } else { 
      this.setState({ 
       isSelected: true 
      }) 
     } 
    }, 

    handleClick: function(listItem) { 
     this.toggleSelected(); 
     this.props.onListItemChange(listItem.props.value); 

     var unboundForEach = Array.prototype.forEach, 
      forEach = Function.prototype.call.bind(unboundForEach); 

     forEach(document.querySelectorAll('ul.cs-select li'), function (el) { 

      // below is trying to 
      // make sure that when a user clicks on a list 
      // item in the SelectableList, then all the *other* 
      // list items get class="selected" removed. 
      // this works for the first time that you move through the 
      // list clicking the other items, but then, on the second 
      // pass through, starts to fail, requiring *two clicks* before the 
      // list item is selected again. 
      // maybe there's a better more "reactive" method of doing this? 

      if (el.dataset.index != listItem.props.index && el.classList.contains('selected')) { 
       el.classList.remove('selected'); 
      } 
     }); 
    }, 

    render: function() { 
     return (
      <li ref={"listSel"+this.props.key} 
       data-value={this.props.value} 
       data-index={this.props.index} 
       className={this.state.isSelected == true ? 'selected' : '' } 
       onClick={this.handleClick.bind(null, this)}> 
       {this.props.content} 
      </li> 
     ); 
    } 
}); 

var SelectableList = React.createClass({ 

    render: function() { 

     var listItems = this.props.options.map(function(opt, index) { 
      return <ListItem key={index} index={index} 
         value={opt.value} content={opt.label} 
         onListItemChange={this.props.onListItemChange.bind(null, index)} />; 
     }, this); 

     return <ul className="cs-select">{ listItems }</ul>; 
    } 

}) 

var CustomSelect = React.createClass({ 

    getInitialState: function() { 
     return { 
      selectedOption: '' 
     } 
    }, 

    handleListItemChange: function(listIndex, listItem) { 
     this.setState({ 
      selectedOption: listItem.props.value 
     }) 
    }, 

    render: function() { 

     var options = [{value:"One", label: "One"},{value:"Two", label: "Two"},{value:"Three", label: "Three"}]; 

     return (
      <div className="group"> 
       <div className="cs-select"> 
        <SelectableList options={options} 
         onListItemChange={this.handleListItemChange} /> 
        <SelectBox className="cs-select" 
         initialValue={this.state.selectedOption} 
         fieldName="custom-select" options={options}/> 
       </div> 
      </div> 
     ) 
    } 
}) 

module.exports = CustomSelect; 

उत्तर

15

माता पिता घटक बच्चों के लिए एक कॉलबैक पारित करना चाहिए, और प्रत्येक बच्चे कि कॉलबैक ट्रिगर करेगा जब अपने राज्य में परिवर्तन। आप वास्तव में माता-पिता में सभी राज्यों को सच्चाई के एक बिंदु के रूप में उपयोग कर सकते हैं, और प्रत्येक बच्चे को "चयनित" मान को प्रोप के रूप में पास कर सकते हैं।

उस मामले में, बच्चे को ऐसा दिखाई दे सकता:

var Child = React.createClass({ 
    onToggle: function() { 
     this.props.onToggle(this.props.id, !this.props.selected); 
    }, 

    render: function() { 
     return <button onClick={this.onToggle}>Toggle {this.props.label} - {this.props.selected ? 'Selected!' : ''}!</button>; 
    } 
}); 

यह कोई राज्य है, यह सिर्फ एक onToggle कॉलबैक जब क्लिक आग गया है। माता-पिता इस प्रकार दिखाई देगा:

var Parent = React.createClass({ 
    getInitialState: function() { 
     return { 
      selections: [] 
     }; 
    }, 
    onChildToggle: function(id, selected) { 
     var selections = this.state.selections; 

     selections[id] = selected; 

     this.setState({ 
      selections: selections 
     }); 
    }, 

    buildChildren: function(dataItem) { 
     return <Child 
      id={dataItem.id} 
      label={dataItem.label} 
      selected={this.state.selections[dataItem.id]} 
      onToggle={this.onChildToggle} /> 
    }, 

    render: function() { 
     return <div>{this.props.data.map(this.buildChildren)}</div> 
    } 
}); 

यह राज्य में चयन की एक सरणी रखती है और जब यह एक बच्चे के कॉलबैक संभालती है, यह setState का उपयोग करता है अपने राज्य selected प्रोप में नीचे पारित करके बच्चों को फिर से प्रस्तुत करने के लिए प्रत्येक बच्चे को।

आप इस यहाँ की एक काम उदाहरण देख सकते हैं:

https://jsfiddle.net/fth25erj/

+0

धन्यवाद कॉलिन। ऐसा लगता है कि मैं यह काम कर सकता हूं। मल्टी-सिलेक्ट विकल्प के बजाय, इसे विशेष रूप से चुनने के लिए ''' 'ChildToggle() '' 'में' '' '' 'की थोड़ी-थोड़ी तर्क की आवश्यकता है। –

+0

और यदि यह एकल चयन है, तो केवल एक ही मान संग्रहीत करें जो चयनित तत्व को दर्शाता है। यह आमतौर पर चयनित डेटा आइटम, या इसकी आईडी का सूचकांक होता है। फिर आप 'चयनित = {this.state.selected === अनुक्रमणिका} 'या' चयनित = {this.state.selected === dataItem.id} कर सकते हैं ' – FakeRainBrigand

0

निम्नलिखित कोड मुझे दो भाई बहन के बीच सेटअप संचार में मदद करता है। सेटअप रेंडर() और घटकडिडमाउंट() कॉल के दौरान उनके माता-पिता में किया जाता है।

class App extends React.Component<IAppProps, IAppState> { 
    private _navigationPanel: NavigationPanel; 
    private _mapPanel: MapPanel; 

    constructor() { 
     super(); 
     this.state = {}; 
    } 

    // `componentDidMount()` is called by ReactJS after `render()` 
    componentDidMount() { 
     // Pass _mapPanel to _navigationPanel 
     // It will allow _navigationPanel to call _mapPanel directly 
     this._navigationPanel.setMapPanel(this._mapPanel); 
    } 

    render() { 
     return (
      <div id="appDiv" style={divStyle}> 
       // `ref=` helps to get reference to a child during rendering 
       <NavigationPanel ref={(child) => { this._navigationPanel = child; }} /> 
       <MapPanel ref={(child) => { this._mapPanel = child; }} /> 
      </div> 
     ); 
    } 
} 
संबंधित मुद्दे