2015-09-18 20 views
0

我有一個工作組件,允許複選框全部和複選框。它完美的作品。但是我討厭這個想法,即每次我想要使用這個特性時,都會被困在所有這些代碼中。我正在尋找一種方式來應對這種模塊化?這是否是模塊化和抽象反應組件功能

它並沒有在一個地方模塊化「輸入全部檢查」功能的全部功能。我必須在每次使用時移動getInitialState變量和changeHandlers。

我認爲它就像是如果「輸入複選框全部」功能在HTML中是原生的,我們將如何使用它?我們只需要爲元素提供屬性,並且它們會互相引用,並且所有處理程序都會在引擎蓋下發生,使用起來會很簡單。這個例子的目標是讓HTML級別簡單。我上面展示的代碼沒有實現,因爲它被綁定到函數處理程序和狀態初始值設定項。反應是否提供了一種抽象的方式?

下面是我對這個組件所需的API。

Here's the working example.

的主要問題是:

  • 的組件功能是淡泊的父母,這意味着paren't並不需要存儲的處理程序和狀態的信息。
  • 該代碼當前手動跟蹤每個複選框的狀態,這意味着無法動態地查找DOM中有多少複選框,而無需聲明它。
  • 整體模塊化和易用性。

下面的代碼:

var InputCheckbox = React.createClass({ 
    getDefaultProps: function() { 
    return { 
     checked: false 
    } 
    }, 
    render: function() { 
    return (
    <input 
      checked={this.props.checked} 
      type='checkbox' 
      {...this.props}/> 
    ) 
    } 
}) 

var Test = React.createClass({ 
    getInitialState: function() { 
    return { 
     checked: [false, false, false] 
    } 
    }, 
    selectAll: function (event) { 
    // Set all checked states to true 
    this.setState({ 
     checked: this.state.checked.map(function() { 
     return event.target.checked 
     }) 
    }) 
    }, 
    handleChange: function (index, event) { 
    var checked = this.state.checked 
    checked[index] = event.target.checked 
    this.setState({ 
     checked: checked 
    }) 
    }, 
    render: function() { 
    var isAllChecked = this.state.checked.filter(function (c) { 
     return c 
     }).length === this.state.checked.length 

    return (
    <div> 
     Select All: 
     <InputCheckbox onChange={this.selectAll} checked={isAllChecked}/> 
     <br/> 
     <InputCheckbox checked={this.state.checked[0]} onChange={this.handleChange.bind(this, 0)}/> 
     <br/> 
     <InputCheckbox checked={this.state.checked[1]} onChange={this.handleChange.bind(this, 1)}/> 
     <br/> 
     <InputCheckbox checked={this.state.checked[2]} onChange={this.handleChange.bind(this, 2)}/> 
     <br/> 
    </div> 
    ) 
    } 
}) 

React.render(<Test/>, document.body) 

理想的情況下我就可以這樣使用它:

var Checkbox = require('./Checkbox') 

var Test = React.createClass({ 
    render: function() { 
    return (
     <div> 
     <Checkbox id="alpha"/> 
     <Checkbox htmlFor="alpha"/> 
     <Checkbox htmlFor="alpha"/> 
     <Checkbox htmlFor="alpha"/> 
     </div> 
    ) 
    } 
}) 
+0

現在您有Test組件來管理複選框的狀態。最好將該邏輯移入Store。然後將每個複選框包裝到一個包裝組件中,該組件從商店讀取'checked'狀態並將其作爲道具傳遞到複選框中。 – oluckyman

+0

@oluckyman嘿,你能證明在答案中看起來像什麼嗎? 「包裝每個複選框」有點困惑你的意思。 – ThomasReggi

+0

將數據提取到商店中將與所要求的相反 - 任何鏈接到商店的組件都不能在不同的區域或應用程序中重複使用 – Glenjamin

回答

1

下面的例子是在正確的大方向,我認爲,總的想法是,以引入相關框的包裝組件,然後遍歷該組件中的孩子將它們綁定在一起。

var CheckAll = React.createClass({ 
render() { 
    return <input type="checkbox" {...this.props} /> 
} 
}); 
var Checkbox = React.createClass({ 
render() { 
    return <input type="checkbox" {...this.props} /> 
} 
}); 
var CheckboxGroup = React.createClass({ 
setAll(to) { 
    var result = {}; 
    Object.keys(this.props.boxes).forEach(k => result[k] = to) 
    this.props.onChange(result); 
}, 
setOne(name, to) { 
    var result = {}; 
    Object.keys(this.props.boxes).forEach(k => result[k] = this.props.boxes[k]) 
    result[name] = to; 
    this.props.onChange(result); 
}, 
enrichChild(child) { 
    var boxes = this.props.boxes; 
    var all = Object.keys(boxes).every(k => boxes[k]); 
    if (child.type == CheckAll) { 
    return React.cloneElement(child, { checked: all, 
     onChange:() => this.setAll(!all) 
    }); 
    } else if (child.type == Checkbox) { 
    var name = child.props.name; 
    return React.cloneElement(child, { checked: !!boxes[name], 
     onChange: ({target}) => this.setOne(name, target.checked) 
    }); 
    } else { 
    return child; 
    } 
}, 
render() { 
    return (
    <div> 
     {React.Children.map(this.props.children, this.enrichChild)} 
    </div> 
) 
} 
}); 


var Test = React.createClass({ 
    getInitialState: function() { 
    return { 
     boxes: { 
     a: true, 
     b: false, 
     c: false, 
     } 
    } 
    }, 
    render: function() { 
    return (
    <div> 
     <CheckboxGroup 
     boxes={this.state.boxes} 
     onChange={boxes => this.setState({boxes})} 
     > 
     <CheckAll /> 
     <Checkbox name="a" /> 
     <Checkbox name="b" /> 
     <Checkbox name="c" /> 
     </CheckboxGroup> 
    </div> 
    ) 
    } 
}) 

React.render(<Test/>, document.body) 

這裏有一個jsbin - https://jsbin.com/zomuxolevo/1/edit?js,output

爲了能夠與孩子們更多的靈活性,你需要遞歸走他們使用這樣的主旨https://gist.github.com/dandelany/1ff06f4fa1f8d6f89c5e

var RecursiveChildComponent = React.createClass({ 
    render() { 
    return <div> 
     {this.recursiveCloneChildren(this.props.children)} 
    </div> 
    }, 
    recursiveCloneChildren(children) { 
    return React.Children.map(children, child => { 
     if(!_.isObject(child)) return child; 
     var childProps = {someNew: "propToAdd"}; 
     childProps.children = this.recursiveCloneChildren(child.props.children); 
     return React.cloneElement(child, childProps); 
    }) 
    } 
}) 
+0

好的工作。有一個主要問題,當我在表格或段落內或地圖無法找到的地方放置「」時。 ''必須是''下的頂級元素。對於大多數用例而言,這是行不通的。 – ThomasReggi

+0

我已更新示例以顯示如何讓孩子不是頂級元素。 – Glenjamin

0

我砍死了一起使用一些jQuery和lodash。

Here's the example running.

注意,這個例子進入DOM獲得所需的數據。這些複選框的狀態都不存儲在組件中。據我所知,沒有真正的「反應」方式來做到這一點。 (我非常樂意提供建議。)

var Checkbox = React.createClass({ 
    componentDidMount: function() { 
    var component = React.findDOMNode(this) 
    var $component = $(component) 
    if ($component.attr('id')) { 
     var selector = 'input' 
     selector += '[data-component=Checkbox]' 
     selector += '[for=' + $component.attr('id') + ']' 
     var $forComponents = $(selector) 
     $component.on('change', function() { 
     var value = $component.prop('checked') 
     $forComponents.each(function() { 
      $forComponent = $(this) 
      $forComponent.prop('checked', value) 
     }) 
     }) 
     $forComponents.on('change', function() { 
     var values = $forComponents.map(function() { 
      var $forComponent = $(this) 
      var value = $forComponent.prop('checked') 
      return value 
     }) 
     var simple = _.chain(values).unique().value() 
     if (simple.length === 1 && simple[0] === true) { 
      $component.prop('checked', true) 
     } else { 
      $component.prop('checked', false) 
     } 
     }) 
    } 
    }, 
    render: function() { 
    return (
    <input 
     type='checkbox' 
     data-component='Checkbox' 
     {...this.props}/> 
    ) 
    } 
}) 

var Test = React.createClass({ 
    render: function() { 
    return (
    <div> 
     Select All: <Checkbox id='alpha'/><br/> 
     <Checkbox htmlFor='alpha'/><br/> 
     <Checkbox htmlFor='alpha'/><br/> 
     <Checkbox htmlFor='alpha' defaultChecked/><br/> 
     <Checkbox htmlFor='alpha'/><br/> 
     <Checkbox htmlFor='alpha'/><br/> 
    </div> 
    ) 
    } 
}) 

React.render(<Test/>, document.body)