2015-01-09 14 views
6

मुझे ReactJS सीखने में मदद करने के तरीके के रूप में, मैं कुछ ऐसा स्थापित कर रहा हूं जो वास्तव में आसान होना चाहिए, लेकिन मेरे लिए कुछ मुश्किल साबित हुआ है।ReactJS - प्रबंधित चेकबॉक्स समूह

मैं ReactJS में कुछ प्रबंधित चेकबॉक्स समूह सेट अप करना चाहता हूं। एचटीएमएल में, एक चेकबॉक्स "फ़ील्ड" में वास्तव में कई इनपुट प्रकार = "चेकबॉक्स" तत्व होते हैं जो एक सामान्य NAME प्रॉपर्टी साझा करते हैं। जैसा कि मैं इसे समझता हूं, यह केवल यूआई तत्व का प्रकार है जिसे रेक्टजेएस की रचनात्मक प्रकृति को फिट करना चाहिए।

मैं दो ReactJS घटक:

पहले, CheckboxField चेकबॉक्स समूह में प्रत्येक व्यक्ति के प्रवेश के लिए है - यानी, प्रत्येक इनपुट प्रकार = "checkbox" HTML तत्व।

दूसरा, चेकबॉक्स फ़ील्ड समूह समूहबॉक्स प्रविष्टियों के प्रत्येक समूह के लिए है - यानी HTML तत्वों का प्रत्येक समूह जो एक सामान्य NAME प्रॉपर्टी साझा करता है। चेकबॉक्स फ़ील्ड समूह घटक इसमें प्रारंभ किए गए प्रारंभिक प्रोप के आधार पर कई चेकबॉक्स फ़ील्ड घटक बनाता है।

राज्य व्यक्तिगत चेकबॉक्स फ़ील्ड स्तर की बजाय चेकबॉक्स फ़ील्ड समूह घटक में प्रबंधित किया जाता है। जो मैंने पढ़ा है, उससे आपको राज्य को उच्चतम स्तर के रूप में प्रबंधित करना चाहिए जो समझ में आता है। और मेरे लिए, यह चेकबॉक्स फ़ील्ड समूह स्तर पर रखने के लिए और अधिक समझ में आता है।

जब चेकबॉक्स फ़ील्ड समूह पहले चलता है, तो इसकी प्रारंभिक स्थिति एक प्रारंभिक प्रोप से, एक सरणी के रूप में, एक सरणी के रूप में बनाई जाती है। रेंडर विधि (वास्तव में रेंडर विकल्प विधि) अपने राज्य सरणी के माध्यम से लूप करती है, और प्रत्येक राज्य सदस्य की गुणों को बाद में प्रोप के रूप में चेकबॉक्स फ़ील्ड घटक में भेज देती है। जब उपयोगकर्ता चेकबॉक्स में से किसी एक को चिपकता/हटाता है, तो उस ईवेंट को कॉलबैक के माध्यम से कॉलबैक के माध्यम से पास किया जाता है, चेकबॉक्स फ़ील्ड समूह, उसके मालिक का चेंज विधि। यह विधि निर्धारित करती है कि कौन से चेकबॉक्स को उसकी आईडी प्रॉपर्टी पूछताछ करके बदल दिया गया है, और फिर सेटस्टेट() कॉल के माध्यम से चेकबॉक्स फ़ील्ड समूह के स्टेट सरणी के सही सदस्य को संबंधित परिवर्तन करता है। यह चेकबॉक्स फ़ील्ड समूह को स्वचालित रूप से फिर से प्रस्तुत करने का कारण बनता है, नए राज्य सरणी को व्यक्तिगत चेकबॉक्स फ़ील्ड घटकों में पारित किया जा रहा है, ताकि सबकुछ सिंक हो।

/** @jsx React.DOM */ 
 

 
var CheckboxField = React.createClass({ 
 
    propTypes: { 
 
     values: React.PropTypes.object.isRequired 
 
    }, 
 
    getDefaultProps: function() { 
 
     return { 
 
      values: { 
 
       label: "Place holder text"     
 
      } 
 
     }; 
 
    }, 
 
    render: function() { 
 
     return (
 
      <label htlmFor={this.props.values.id}> 
 
       <input type="checkbox" 
 
        name={this.props.values.name} 
 
        id={this.props.values.id} 
 
        value={this.props.values.value} 
 
        checked={this.props.values.checked} 
 
        onChange={this.handleChange} /> 
 
       {this.props.values.label} <br /> 
 
      </label> 
 
     ); 
 
    }, 
 
    handleChange: function(event) { 
 
     // Should use this to set parent's state via a callback func. Then the 
 
     // change to the parent's state will generate new props to be passed down 
 
     // to the children in the render(). 
 
     this.props.callBackOnChange(this, event.target.checked); 
 
    } 
 
}); 
 

 

 
var CheckboxFieldGroup = React.createClass({ 
 
    propTypes: { 
 
     defaultValues: React.PropTypes.object.isRequired 
 
    }, 
 
    getInitialState: function() { 
 
     // default props passed in to CheckboxFieldGroup (this componenent) will be used to set up the state. State 
 
     // is stored in this component, and *not* in the child CheckboxField components. The state store in this 
 
     // component will, in turn, generate the props for the child CheckboxField components. When the latter 
 
     // are updated (i.e. clicked) by the user, then the event will call the handleChange() function in 
 
     // this component. That will generate update this component's state, which in turn will generate 
 
     // new props for the child CheckboxField components, which will cause those components to re-render! 
 
     var that = this; 
 
     var initStateArray = this.props.defaultValues.valuesArray.map(function(choice, i) { 
 
      var tempObj = { 
 
       name: that.props.defaultValues.name, 
 
       value: choice.value, 
 
       label: choice.label, 
 
       id: _.uniqueId("choice"), 
 
       checked: choice.checked 
 
      }; 
 
      return tempObj; 
 
     }); 
 
     return {valuesArray: initStateArray}; 
 
    }, 
 
    renderChoices: function() { 
 
     var that = this; // Could also use .bind(this) on our map() function but that requires IE9+. 
 
     return this.state.valuesArray.map(function(choice, i) { 
 
      return CheckboxField({ 
 
       values: { 
 
        name: that.props.defaultValues.name, 
 
        value: choice.label, 
 
        label: choice.label, 
 
        id: choice.id, 
 
        checked: choice.checked 
 
       }, 
 
       callBackOnChange: that.handleChange 
 
      }); 
 
     }); 
 
    }, 
 
    render: function() { 
 
     return (
 
      <form> 
 
       {this.renderChoices()} 
 
      </form> 
 
     ); 
 
    }, 
 
    handleChange: function(componentChanged, newState) { 
 
     // Callback function passed from CheckboxFieldGroup (this component) to each of the 
 
     // CheckboxField child components. (See renderChoices func). 
 
     var idx = -1; 
 
     var stateMemberToChange = _.find(this.state.valuesArray, function(obj, num) { 
 
      idx = num; 
 
      return obj.id === componentChanged.props.values.id; 
 
     }); 
 

 
     // Threw an error when I tried to update and indiviudal member of the state array/object. So, take a copy 
 
     // of the state, update the copy and do a setState() on the whole thing. Using setState() rather than 
 
     // replaceState() should be more efficient here. 
 
     var newStateValuesArray = this.state.valuesArray; 
 
     newStateValuesArray[idx].checked = newState; 
 
     this.setState({valuesArray: newStateValuesArray}); // Automatically triggers render() !! 
 
    }, 
 
    getCheckedValues: function() { 
 
     // Get an array of state objects that are checked 
 
     var checkedObjArray = []; 
 
     checkedObjArray = _.filter(this.state.valuesArray, function(obj){ 
 
      return obj.checked; 
 
     }); 
 

 
     // Get an array of value properties for the checked objects 
 
     var checkedArray = _.map(checkedObjArray, function(obj){ 
 
      return obj.value; 
 
     }); 
 
     console.log("CheckboxFieldGroup.getCheckedValues() = " + checkedArray); 
 
    }, 
 
    componentDidMount: function() { 
 
     this.getCheckedValues(); 
 
    }, 
 
    componentDidUpdate: function() { 
 
     this.getCheckedValues(); 
 
    } 
 
}); 
 

 

 
var defaults = { 
 
    name : "mikeyCheck", 
 
    valuesArray : [{ 
 
     label : "My Checkbox Field", 
 
     value: "MyCheckboxField", 
 
     checked : false 
 
    }, { 
 
     label : "My Other Checkbox Field", 
 
     value : "MyOtherCheckboxField", 
 
     checked : false 
 
    }, { 
 
     label : "Yet Another Checkbox Field", 
 
     value : "YetAnotherCheckboxField", 
 
     checked : true 
 
    },{ 
 
     label : "Yes, it's a fourth checkbox field", 
 
     value : "YesItsAFourthCheckboxField", 
 
     checked : false 
 
    }] 
 
}; 
 

 
React.renderComponent(<CheckboxFieldGroup defaultValues={defaults} />, document.getElementById("main"));

यह सब ठीक काम करता है, और यहाँ एक JSFiddle of it in operation है।

फिर भी मुझे लगता है कि मैंने यहां कई चीजें गलत की हैं।

  1. ऐसा कुछ आसान हासिल करने के लिए कोड का एक बहुत भयानक लगता है। क्या मेरा पूरा दृष्टिकोण गुमराह है?
  2. मेरे चेकबॉक्स फ़ील्ड ग्रुप की स्थिति में बहुत सारी चीज़ें शामिल हैं जो शायद वहां नहीं होनी चाहिए, उदा। इसमें नाम, मान, लेबल, आईडी और चेक किया गया है, वास्तव में यह केवल आखिरी नाम है जिसे कभी भी बदला जा रहा है (उपयोगकर्ता द्वारा)। तो क्या यह एकमात्र ऐसा होना चाहिए जो राज्य में है और अन्य किसी भी तरह से प्रोप में हैं? फिर भी मुझे आईडी संपत्ति को राज्य में रहने की आवश्यकता है ताकि चेकबॉक्स फ़ील्ड समूह .andleChange() विधि निर्धारित कर सके कि कौन सा चेकबॉक्स वास्तव में बदल गया है। या क्या ऐसा करने का एक बेहतर/आसान तरीका है?
  3. जब मैं चेकबॉक्स फ़ील्ड समूह घटक की स्थिति को अद्यतन करता हूं, तो हैंडल चेंज() विधि में फिर से, मुझे उस राज्य के एक हिस्से को सीधे अपडेट करने का कोई तरीका नहीं मिला जो मुझे चाहिए - यानी राज्य सरणी तत्व की चेक की गई संपत्ति उस चेकबॉक्स पर जिसे अभी टिकाया गया था/अनचाहे था। मैं जो कर रहा हूं वह राज्य सरणी की एक पूरी प्रतिलिपि को दूसरी चर में ले रहा है, वहां मेरी एक संपत्ति को अपडेट कर रहा है, और फिर पूरे राज्य को नई सरणी के साथ बदल रहा है। क्या यह ऐसा करने का एक कचरा तरीका नहीं है, भले ही मैं setState() को बजायState() का उपयोग कर रहा हूं?

आपकी मदद के लिए, अग्रिम में बहुत धन्यवाद। और हाँ, मेरे पास Google है, और दस्तावेज़ीकरण के बावजूद। मैंने डेवलपिंग एक रिएक्ट एज पुस्तक भी खरीदी और पढ़ी है, जो इस समय एक के क्षेत्र में नंबर एक प्रतीत होता है! प्रश्न संख्या 1 के लिए

उत्तर

4

, मुझे वही महसूस होता है जब मैं पहली बार अपना पहला घटक बनाने के लिए प्रतिक्रिया का उपयोग कर रहा हूं, तो अनुमान है कि यह तरीका है? हाहा

प्रश्न संख्या 2 और 3 के लिए, मैं केवल राज्य में checked बचाऊंगा, और शेष जानकारी प्रोप में बनी रहेगी। फिर अद्यतन को संभालने पर, मैं केवल कुछ चेकबॉक्स को सत्य/गलत पर सेट करता हूं।

http://jsfiddle.net/p0s58exh/4/

getInitialState: function() { 
    var that = this; 
    var states = {}; 
    _.map(this.props.defaultValues.checkboxes, function (choice, key) { 
    states[key] = choice.checked; 
    }); 
    return states; 
}, 

बच्चे सरणी तत्वों के लिए key जोड़ने के लिए याद भी तो प्रतिक्रिया ठीक पता है जो तत्व अद्यतन किया जाना है।

return _.map(this.props.defaultValues.checkboxes, function (choice, key) { 
    return CheckboxField({ 
    key: key, 
    values: { 
     name: that.props.defaultValues.name, 
     value: key, 
     label: choice.label, 
     id: choice.id, 
     checked: that.state[key] 
    }, 
    callBackOnChange: that.handleChange 
    }); 
}); 
+0

यह वही दिखता है जो मैं देख रहा था, चिनकांग, इसके लिए बहुत धन्यवाद। विशेष रूप से कुंजी के बारे में सामान, जिसे मैंने अभी तक नहीं देखा है (या रेफरी!)। जब मुझे इसे विस्तार से जाने का मौका मिला, तो मैं शायद वापस आऊंगा और इसे उत्तर के रूप में चिह्नित करूंगा, हालांकि मैं पहले कुछ और प्रश्न पूछ सकता हूं! – ChillyPenguin

संबंधित मुद्दे