2017-09-06 9 views
0

2つのコンポーネントと1つの親コンポーネントを作成しました。私は彼らのチェックボックスがチェックされていないときに子どもたちのドロップダウンを消させることができるように、どうやってそれらを接続できるかを調べようとしています。私は2つのコンポーネントが通信できないようにこれを作成したかもしれないと思うが、それらを手に入れる方法があるかどうかを見たいと思った。さまざまな方法で試してみましたが、それを理解できないようです。reactjsの通信コンポーネント

これは親コンポーネントです。それは、いくつかのデータからセクションを構築し、ドロップダウンを持つ最初の(親)チェックボックスでチェックボックスツリービューをレンダリングします。このドロップダウンで3番目のオプションを選択すると、各子チェックボックスのドロップダウンが表示されます。チェックボックスをオフにしたときに子ドロップダウンを消させることができるかどうかを確認しようとしていますが、2つのコンポーネントが通信できるようには見えません。

export default class CheckboxGroup extends PureComponent { 
 

 
    static propTypes = { 
 
    data: PropTypes.any.isRequired, 
 
    onChange: PropTypes.func.isRequired, 
 
    counter: PropTypes.number, 
 
    }; 
 

 
    mapParents = (counter, child) => (
 
    <li key={child.get('name')} className='field'> 
 
     <SegmentHeader style={segmentStyle} title={child.get('label')} icon={child.get('icon')}> 
 
     <div className='fields' style={zeroMargin}> 
 
      <div className='four wide field'> 
 
      <TreeCheckbox 
 
       label={`Grant ${child.get('label')} Permissions`} 
 
       counter={counter} 
 
       onChange={this.props.onChange} 
 
      /> 
 
      {child.get('items') && this.buildTree(child.get('items'), counter + child.get('name'))} 
 
      </div> 
 
      <div className='twelve wide field'> 
 
      <GrantDropdown label={child.get('label')} childItems={child.get('items')}/> 
 
      </div> 
 
     </div> 
 
     </SegmentHeader> 
 
    </li> 
 
) 
 

 
    mapDataArr = (counter) => (child) => (
 
    (counter === 0 || counter === 1000) ? 
 
     this.mapParents(counter, child) 
 
     : 
 
     <li key={child.get('name')}> 
 
     <TreeCheckbox label={child.get('label')} onChange={this.props.onChange}/> 
 
     {child.get('items') && this.buildTree(child.get('items'), counter + child.get('name'))} 
 
     </li> 
 
) 
 

 
    buildTree = (dataArr, counter) => (
 
    <ul key={counter} style={listStyle}> 
 
     {dataArr.map(this.mapDataArr(counter))} 
 
    </ul> 
 
) 
 

 
    render() { 
 
    return (
 
     <div className='tree-view'> 
 
     {this.buildTree(this.props.data, this.props.counter)} 
 
     </div> 
 
    ); 
 
    } 
 
}

import React, { PureComponent } from 'react'; 
 
import PropTypes from 'prop-types'; 
 
import { connect } from 'react-redux'; 
 

 
const pointer = { cursor: 'pointer' }; 
 

 
class TreeCheckbox extends PureComponent { 
 
    static propTypes = { 
 
    onChange: PropTypes.func, 
 
    label: PropTypes.string, 
 
    currentPerson: PropTypes.any, 
 
    }; 
 

 
    componentDidMount() { 
 
    if (this.props.currentPerson.get('permissions').includes(this.props.label)) { 
 
     this.checkInput.checked = true; 
 
     this.changeInput(this.checkInput); 
 
    } 
 
    } 
 

 
    getLiParents = (el, parentSelector) => { 
 
    if (!parentSelector) parentSelector = document; // eslint-disable-line 
 
    const parents = []; 
 
    let parent = el.parentNode; 
 
    let o; 
 
    while (parent !== parentSelector) { 
 
     o = parent; 
 
     if (parent.tagName === 'LI') parents.push(o); 
 
     parent = o.parentNode; 
 
    } 
 
    return parents; 
 
    } 
 

 
    traverseDOMUpwards = (startingEl, steps) => { 
 
    let elem = startingEl; 
 
    for (let i = 0; i < steps; i++) { 
 
     elem = elem.parentNode; 
 
    } 
 
    return elem; 
 
    } 
 

 
    markIt = (nodeElem, checkIt, indeter) => { 
 
    const node = nodeElem; 
 
    const up = this.traverseDOMUpwards(node, 1); 
 
    node.checked = checkIt; 
 
    node.indeterminate = indeter; 
 
    this.props.onChange(up.children[1].innerText, checkIt); 
 
    } 
 

 
    changeInput = (event) => { 
 
    const e = event === this.checkInput ? event : event.target; 
 
    const selector = 'input[type="checkbox"]'; 
 
    const querySelector = (el) => el.querySelectorAll(selector); 
 
    const container = this.traverseDOMUpwards(e, 2); 
 
    const markAllChildren = querySelector(container.parentNode); 
 
    const checked = e.tagName === 'LABEL' ? !markAllChildren[0].checked : e.checked; 
 
    const siblingsCheck = (element) => { 
 
     let onesNotRight = false; 
 
     const sibling = [].slice.call(element.parentNode.children); 
 
     sibling.filter(child => child !== element).forEach(elem => { 
 
     if (querySelector(elem)[0].checked !== querySelector(element)[0].checked) { 
 
      onesNotRight = true; 
 
     } 
 
     }); 
 
     return !onesNotRight; 
 
    }; 
 
    const checkRelatives = (ele) => { 
 
     let el = ele; 
 
     if (el.tagName === 'DIV') el = el.parentNode; 
 
     if (el.tagName !== 'LI') return; 
 
     const parentContainer = this.traverseDOMUpwards(el, 2); 
 
     if (siblingsCheck(el) && checked) { 
 
     this.markIt(querySelector(parentContainer)[0], true, false); 
 
     checkRelatives(parentContainer); 
 
     } else if (siblingsCheck(el) && !checked) { 
 
     const parent = this.traverseDOMUpwards(el, 2); 
 
     const indeter = parent.querySelectorAll(`${selector}:checked`).length > 0; 
 
     this.markIt(querySelector(parent)[0], false, indeter); 
 
     checkRelatives(parent); 
 
     } else { 
 
     for (const child of this.getLiParents(el)) { 
 
      this.markIt(querySelector(child)[0], false, true); 
 
     } 
 
     } 
 
    }; 
 

 
    for (const children of markAllChildren) { 
 
     this.markIt(children, checked, false); 
 
    } 
 

 
    checkRelatives(container); 
 
    }; 
 

 
    getRef = (input) => { this.checkInput = input; } 
 

 
    render() { 
 
    const { label } = this.props; 
 

 
    return (
 
     <div className='permission-item'> 
 
     <div className='ui checkbox'> 
 
      <input type='checkbox' onChange={this.changeInput} ref={this.getRef}/> 
 
      <label onClick={this.changeInput} style={pointer}> 
 
      {label} 
 
      </label> 
 
     </div> 
 
     </div> 
 
    ); 
 
    } 
 
} 
 

 
const mapStatetoProps = (state) => ({ 
 
    currentPerson: state.get('currentPerson'), 
 
}); 
 
export default connect(mapStatetoProps)(TreeCheckbox);

class GrantDropdown extends AbstractSettingsComponent { 
 
    static propTypes = { 
 
    label: PropTypes.string, 
 
    currentPerson: PropTypes.any, 
 
    counter: PropTypes.number, 
 
    permissionOptions: PropTypes.any, 
 
    }; 
 

 
    state = { 
 
    items: new List(), 
 
    } 
 

 
    componentDidMount() { 
 
    if (this.props.childItems) { 
 
     this.getAllChildLabels(this.props.childItems); 
 
    } 
 
    } 
 

 
    getAllChildLabels = (childItems) => { 
 
    let list = new List(); 
 
    for (const item of childItems) { 
 
     list = list.push(item.get('label')); 
 
     if (item.get('items')) { 
 
     for (const childItem of item.get('items')) { 
 
      list = list.push(childItem.get('label')); 
 
     } 
 
     } 
 
    } 
 
    this.setState({ items: list }); 
 
    } 
 

 
    handlePermissionChange = (label) => (e, { value }) => { 
 
    this.updatePerson(['locationsPermissionsMap', label], value); 
 
    } 
 

 
    mapItems = (val, i) => { // eslint-disable-line 
 
    const locationVal = this.props.currentPerson.getIn(['locationsPermissionsMap', val]); 
 
    return (
 
     <div className={locationVal === 2 ? 'two fields' : 'field'} style={zeroMarginBottom} key={i}> 
 
      <OptionSelector 
 
      options={this.firstThreePermissionOpt()} 
 
      defaultValue={locationVal || 0} 
 
      onChange={this.handlePermissionChange(val)} 
 
      /> 
 
      {locationVal === 2 && 
 
      <div className='field' style={zeroMarginBottom}> 
 
       <LocationMultiSelect name={val} {...this.props}/> 
 
      </div> 
 
      } 
 
     </div> 
 
    ); 
 
    } 
 

 
    render() { 
 
    const { label, currentPerson } = this.props; 
 
    if (!currentPerson.get('permissions').includes(label)) { 
 
     return null; 
 
    } 
 
    const locationLabel = currentPerson.getIn(['locationsPermissionsMap', label]); 
 
    return (
 
     <div className={ locationLabel === 2 ? 'two fields' : 'field'} style={zeroMarginBottom}> 
 
     <div className='field'> 
 
      <OptionSelector 
 
      options={this.getPermissionOptions()} 
 
      defaultValue={currentPerson.getIn(['locationsPermissionsMap', label]) || 0} 
 
      onChange={this.handlePermissionChange(label)} 
 
      /> 
 
      {locationLabel === 3 && this.state.items.map(this.mapItems)} 
 
     </div> 
 
     {locationLabel === 2 && 
 
      <div className='field'> 
 
      <LocationMultiSelect name={label} {...this.props}/> 
 
      </div> 
 
     } 
 
     </div> 
 
    ); 
 
    } 
 
} 
 
const mapStatetoProps = (state) => ({ 
 
    currentPerson: state.get('currentPerson'), 
 
    locations: state.get('locations'), 
 
}); 
 
export default connect(mapStatetoProps)(GrantDropdown);

答えて

1

何をする子コンポーネントに送信する小道具のカップルを設定して行うことができ、それらを再レンダリング:
はここで、このような行動の小さな一例です。

export default class CheckBoxComponent extends React.Component { 
     changeInput() { 
      this.props.onCheckedChanged(); 
     } 

     render() { 
     return(
      <div className='permission-item'> 
      <div className='ui checkbox'> 
       <input type='checkbox' onChange={this.changeInput} ref={this.getRef}/> 
       <label onClick={this.changeInput.bind(this)} style={pointer}> 
       {label} 
       </label> 
      </div> 
      </div> 
     ) 
     } 
    } 

    export default class DropDownComponent extends React.Component { 
     renderSelect() { 
     // here render your select and options 
     } 
     render() { 
     return(
      <div> 
      {this.props.checkboxChecked === false ? this.renderSelect : null} 
      </div> 
     ) 
     } 
    } 

    export default class App extends React.Component { 
     constructor(props) { 
      super(props); 
      this.state = { 
       checkboxChecked: false 
      }; 
     } 
     onCheckedChanged() { 
      this.setState({ checkboxChecked: !this.state.checkboxChecked }); 
     } 
     render() { 
      return(
       <div> 
        <CheckBoxComponent onCheckedChanged={this.onCheckedChanged.bind(this)} /> 
        <DropDownComponent checkboxChecked={this.state.checkboxChecked} /> 
       </div> 
      ) 
     } 
    } 
+0

私はこの方法がうまくいくかもしれないと思っていますが、私が提供したコードにそれをどのように追加するかは不明です。私はいくつかの方法で試しましたが、うまくいきませんでしたが、意味があります、私はそれを間違っていると思います。 – StuffedPoblano

1

ハンドラはの名前を得ることができるので、あなたはあなたの状態で対応するプロパティへ<input/> name属性を設定することができますイベントパラメータを介してリスト/入力し、状態をそれぞれ設定する。
次に、Dropdownを状態に応じて条件付きでレンダリングすることができます。

const lists = [ 
 
    [ 
 
    { value: "0", text: "im 0" }, 
 
    { value: "1", text: "im 1" }, 
 
    { value: "2", text: "im 2" } 
 
    ], 
 
    [ 
 
    { value: "a", text: "im a" }, 
 
    { value: "b", text: "im b" }, 
 
    { value: "c", text: "im c" } 
 
    ] 
 
]; 
 

 
const DropDown = ({ options }) => { 
 
    return (
 
    <select> 
 
     {options.map(opt => <option value={opt.value}>{opt.text}</option>)} 
 
    </select> 
 
); 
 
}; 
 

 
class App extends React.Component { 
 
    constructor(props) { 
 
    super(props); 
 
    this.state = { 
 
     showList0: false, 
 
     showList1: true 
 
    }; 
 
    this.toggleCheck = this.toggleCheck.bind(this); 
 
    } 
 

 
    toggleCheck(e) { 
 
    const listName = e.target.name; 
 
    this.setState({ [listName]: !this.state[listName] }); 
 
    } 
 

 
    render() { 
 
    return (
 
     <div> 
 
     {lists.map((o, i) => { 
 
      const listName = `showList${i}`; 
 
      const shouldShow = this.state[listName]; 
 
      return (
 
      <div> 
 
       <input 
 
       type="checkbox" 
 
       name={listName} 
 
       checked={shouldShow} 
 
       onChange={this.toggleCheck} 
 
       /> 
 
       {shouldShow && <DropDown options={o} />} 
 
      </div> 
 
     ); 
 
     })} 
 
     </div> 
 
    ); 
 
    } 
 
} 
 

 
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> 
 
<div id="root"></div>

+0

これは、私はあなたが見ることができるものから、私の含まれるコードに組み込むことができるものですか? – StuffedPoblano

関連する問題