2015-01-09 2 views
6

ReactJS를 배우는 데 도움이되는 방법으로, 나는 정말로 쉬워야하는 것을 설정하고 있지만, 다소 까다로운 것으로 판명되었습니다.ReactJS - 관리 체크 박스 그룹

ReactJS에서 일부 관리 체크 박스 그룹을 설정하고 싶습니다. HTML에서, "필드"체크 박스는 실제로 공통 NAME 속성을 공유하는 여러 입력 유형 = "체크 박스"요소로 구성됩니다. 내가 이해하는 바와 같이, 이것은 ReactJS의 구성 적 특성에 맞는 UI 요소 일뿐입니다.

나는 두 ReactJS 구성 요소가 :

첫째, CheckBoxField를 체크 박스 그룹의 각 개별 항목입니다 - 즉, 각 입력 유형 = "체크 박스"HTML 요소.

둘째, CheckboxFieldGroup은 확인란 항목 (예 : 공통 NAME 속성을 공유하는 각 HTML 묶음)의 각 그룹에 대한 것입니다. CheckboxFieldGroup 구성 요소는 전달 된 초기 소품을 기반으로 여러 CheckboxField 구성 요소를 만듭니다.

상태는 개별 CheckboxField 수준이 아닌 CheckboxFieldGroup 구성 요소에서 관리됩니다. 내가 읽은 바에 따르면, 당신은 상태를 가장 높은 수준으로 관리해야합니다. 그리고 나에게 그것은 CheckboxFieldGroup 수준에서 그것을 갖는 것이 더 합리적입니다.

CheckboxFieldGroup을 처음 실행하면 초기 상태가 초기 소품과 배열로 배열로 만들어집니다. render 메서드 (실제로는 renderChoices 메서드)는 상태 배열을 반복하며 각 상태 멤버의 속성을 CheckboxField 구성 요소로 후자의 소품으로 전달합니다. 사용자가 체크 박스 중 하나를 체크하거나 체크하지 않으면 해당 이벤트는 콜백을 통해 CheckboxFieldGroup의 handleChange 메소드 인 소유자로 전달됩니다. 이 메서드는 id 속성을 조사하여 변경된 체크 박스를 확인한 다음 setState() 호출을 통해 CheckboxFieldGroup의 상태 배열에 해당하는 멤버를 변경합니다. 이로 인해 CheckboxFieldGroup이 자동으로 다시 렌더링되고 새 상태 배열이 개별 CheckboxField 구성 요소로 전달되므로 모든 것이 동기화됩니다.

이 모두 잘 작동

/** @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. 내 CheckboxFieldGroup의 상태에 많은 항목이 포함 된 것 같습니다. 이름, 값, 레이블, ID 및 체크가 포함되어 있습니다. 실제로 마지막으로 이름이 바뀌었을 때 (사용자에 의해) 변경 될 것입니다. 어쨌든 그것은 주에있는 유일한 사람이고 다른 사람들은 소품에 있어야합니까? 그러나 CheckboxFieldGroup.handleChange() 메서드가 실제로 변경된 체크 박스를 결정할 수 있도록 상태 속성이 필요합니다. 아니면 이것을하는 더 나은/쉬운 방법이 있습니까?
  3. handleChange() 메서드에서 CheckboxFieldGroup 구성 요소의 상태를 다시 업데이트하면 필요한 상태의 한 부분을 직접 업데이트 할 수있는 방법을 찾을 수 없습니다. 즉, 해당 상태 배열 요소의 checked 속성 그냥 체크 된/체크되지 않은 체크 박스로. 내가 한 일은 결국 상태 배열의 전체 복사본을 다른 변수로 가져 와서 거기에있는 하나의 속성을 업데이트 한 다음 전체 배열을 새로운 배열로 바꾸는 것입니다. replaceState() 대신 setState()를 사용하고 있는데도 이렇게하는 것은 낭비가 아니니?

미리 도움을 주셔서 감사합니다. 그리고 네, 저는 Google을 가지고 있으며 문서를 꼼꼼히 살펴 보았습니다. 나는 또한 순간적으로 하나의 분야에서 1 위를 차지하는 React Edge 개발 책을 사서 읽었습니다!

답변

4

질문 번호 1의 경우 처음 반응을 사용하여 첫 번째 구성 요소를 만들 때와 같은 느낌입니다. 질문 번호 2와 3의 경우

인 경우에만 checked만을 저장하고 나머지 정보는 소품에 남아 있습니다. 그런 다음 업데이트를 처리 할 때 특정 확인란 만 true/false로 설정합니다.

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

너무 너무 업데이트 할 수있는 요소를 정확하게 알고 반응 자식 배열 요소에 key를 추가하는 것을 기억

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

.

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

그게 바로 내가 뭘 찾고 있었는지, ChinKang, 그렇게 많은 감사합니다. 특히 내가 아직 보지 못했던 Key에 관한 것들 (또는 Refs!). 세부 사항을 자세히 살펴볼 기회가 생겼을 때, 나는 더 많은 질문이 먼저 나올 지 모르지만, 다시 돌아와 대답으로 표시 할 것입니다! – ChillyPenguin

관련 문제