Reactjs 向React.DOM元素动态添加事件处理程序
我正在使用RadioButtonGroup组件,该组件类似于单选输入,但带有按钮: 如果组件的使用像这样简单就好了:Reactjs 向React.DOM元素动态添加事件处理程序,reactjs,Reactjs,我正在使用RadioButtonGroup组件,该组件类似于单选输入,但带有按钮: 如果组件的使用像这样简单就好了: var SelectThing = React.createClass({ render: function render() { // I would not like to add onClick handler to every button element // outside the RadioButtonGroup compo
var SelectThing = React.createClass({
render: function render() {
// I would not like to add onClick handler to every button element
// outside the RadioButtonGroup component
return (
<RadioButtonGroup onChange={this._onActiveChange}>
<button>Thing 1</button>
<button>Thing 2</button>
<button>Thing 3</button>
</RadioButtonGroup>
)
},
_onActiveChange: function _onActiveChange(index) {
console.log('You clicked button with index:', index);
}
});
var SelectThing=React.createClass({
render:函数render(){
//我不想向每个按钮元素添加onClick处理程序
//在RadioButtonGroup组件外部
返回(
事情1
事情2
事情3
)
},
_onActiveChange:函数_onActiveChange(索引){
log('您单击了带有索引的按钮:',索引);
}
});
真正的问题是:我如何才能用React最优雅地做到这一点?(我发现了,但它并没有完全回答这个问题)
我的第一个直觉是在组件内部添加和删除onClick处理程序,以从组件的用户中删除锅炉板代码。我想到的另一个选择是给出例如
元素而不是按钮元素,并将它们放在RadioButtonGroup组件中创建的按钮元素中。我不太喜欢后者,因为与传递按钮相比,它在语义上没有多大意义
下面是组件(显然不工作)现在的样子:
// Radio input with buttons
// http://getbootstrap.com/javascript/#buttons-checkbox-radio
var RadioButtonGroup = React.createClass({
getInitialState: function getInitialState() {
return {
active: this.props.active || 0
};
},
componentWillMount: function componentWillMount() {
var buttons = this.props.children;
buttons[this.props.active].className += ' active';
var self = this;
buttons.forEach(function(button, index) {
// How to dynamically set onclick handler for virtual dom
// element created inside JSX?
button.addEventListener('onClick', function(event) {
self._onAnyButtonClick(index, event);
}
});
},
componentWillUnmount: function componentWillUnmount() {
var buttons = this.props.children;
buttons.forEach(function(button, index) {
button.removeEventListener('onClick');
});
},
render: function render() {
return (
<div className="radio-button-group">
{buttons}
</div>
)
},
_onAnyButtonClick: function _onAnyButtonClick(index, event) {
this.setState({
active: index
});
this.props.onChange(index);
}
});
//带按钮的单选输入
// http://getbootstrap.com/javascript/#buttons-复选框收音机
var RadioButtonGroup=React.createClass({
getInitialState:函数getInitialState(){
返回{
活动:this.props.active | | 0
};
},
componentWillMount:函数componentWillMount(){
var buttons=this.props.children;
按钮[this.props.active].className+=“active”;
var self=这个;
按钮。forEach(功能(按钮、索引){
//如何为虚拟dom动态设置onclick处理程序
//在JSX中创建的元素?
addEventListener('onClick',函数(事件){
self.\u onanybutton单击(索引、事件);
}
});
},
componentWillUnmount:函数componentWillUnmount(){
var buttons=this.props.children;
按钮。forEach(功能(按钮、索引){
按钮。removeEventListener('onClick');
});
},
render:函数render(){
返回(
{按钮}
)
},
_onAnyButtonClick:函数_onAnyButtonClick(索引、事件){
这是我的国家({
活动:索引
});
此.props.onChange(索引);
}
});
如果不想弄乱每个按钮上的单击处理程序,只需侦听容器上的单击。然后根据单击的子项更新状态
此外,使用React,最好将所有DOM内容保留在render函数中。在本例中,定义元素的类名
这是如何工作的:
var RadioButtonGroup = React.createClass({
getInitialState: function getInitialState() {
return {
active: this.props.active || 0
};
},
clickHandler: function clickHandler(e) {
// Getting an array of DOM elements
// Then finding which element was clicked
var nodes = Array.prototype.slice.call( e.currentTarget.children );
var index = nodes.indexOf( e.target );
this.setState({ active: index });
},
render: function render() {
var buttons = this.children.map(function(child, i) {
if (i === this.state.active) child.props.className += ' active';
return child;
}, this);
return (
<div className="radio-button-group" onClick={ this.clickHandler }>
{ buttons }
</div>
)
}
});
var RadioButtonGroup=React.createClass({
getInitialState:函数getInitialState(){
返回{
活动:this.props.active | | 0
};
},
clickHandler:函数clickHandler(e){
//获取DOM元素数组
//然后查找单击了哪个元素
var节点=Array.prototype.slice.call(e.currentTarget.children);
var索引=节点。索引of(e.target);
this.setState({active:index});
},
render:函数render(){
var buttons=this.children.map(函数(child,i){
如果(i==this.state.active)child.props.className+='active';
返回儿童;
},这个);
返回(
{按钮}
)
}
});
要获得这样的api(类似于
),我们需要使用cloneWithProps插件
测试1
测试2
测试3
所有这一切只需获取每个子级,添加一个单击处理程序,并有条件地向其添加一个“active”类名。您可以(并且应该)轻松地对其进行修改,以将active类名作为一个道具
var RadioButtonGroup=React.createClass({
render:function(){
返回{React.Children.map(this.props.Children,this.renderItem)}
},
renderItem:函数(按钮、索引){
返回React.cloneElement(按钮{
类名:this.props.value==索引“活动”:“,
onClick:function(){
此.props.onChange(索引);
}.绑定(此),
关键词:索引
});
}
});
如果您不想使用cloneWithProps,可以使用包装器div,但样式可能要复杂一些
renderItem:函数(按钮、索引){
返回React.createElement('div'{
类名:this.props.value==索引“活动”:“,
onClick:function(){
此.props.onChange(索引);
}.绑定(此),
关键词:索引
},按钮);
}
所有东西都使用索引的原因是,您正在传递不透明的react元素。没有干净的方法可以从这些按钮中获取任何数据,但我们确实知道它们的索引,因为我们使用react.Children.map对它们进行迭代。另一种api如下所示:
var SelectThing = React.createClass({
render: function render() {
// I would not like to add onClick handler to every button element
// outside the RadioButtonGroup component
return (
<RadioButtonGroup onChange={this._onActiveChange}>
<button>Thing 1</button>
<button>Thing 2</button>
<button>Thing 3</button>
</RadioButtonGroup>
)
},
_onActiveChange: function _onActiveChange(index) {
console.log('You clicked button with index:', index);
}
});
在这里,我们可以迭代this.props.options,将键传递给onChange回调,并将例如“test1”作为值prop。这是我的代码。我不知道这是否是最好的方法,因为我在5小时前才开始使用react。但它工作正常
var LeftPane = React.createClass({
getInitialState: function() {
return {list:[{name:"Item 1",isactive:1},
{name:"Item 2",isactive:0},
{name:"Item 3",isactive:0},
{name:"Item 4",isactive:0},
{name:"Item 5",isactive:0}]};
},
clickHandler: function(index) {
var current_list = this.state.list;
current_list.map(function(record,i){
if(record.isactive==1){
if(i!=index){
record.isactive =0;
}else{
return;
}
}else{
if(i==index){
record.isactive =1;
}
}
});
this.setState({data:current_list});
},
render: function() {
var active_item = "list-group-item active"
var non_active_item ="list-group-item";
var _this = this;
return (
<div className="list-group">
{this.state.list.map(function(record,i) {
if(record.isactive==1){
return <a className={active_item} onClick={_this.clickHandler.bind(null, i)}>{record.name}</a>
}else{
return <a className={non_active_item} onClick={_this.clickHandler.bind(null, i)}>{record.name}</a>
}
})}
</div>
</div>
)
}
});
var LeftPane=React.createClass({
getInitialState:函数(){
返回{list:[{name:“Item 1”,isactive:1},
{名称:“项目2”,i活动:0},
{名称:“项目3”,i活动:0},
{名称:“项目4”,i活动:0},
{名称:“项目5”,i活动:0}]};
},
clickHandler:函数(索引){
var current_list=this.state.list;
当前列表映射(功能(rec