我有一个可点击列表组件的开头,它将用于驱动一个select元素.正如你可以从下面看,onClick的ListItem,我路过一个子元素的状态(ListItem在这种情况下)父母(SelectableList及CustomSelect组件).这工作正常.但是,我还想做的是更改兄弟组件(其他ListItems)的状态,以便在单击其中一个ListItem时切换其选定状态.
目前,我只是使用document.querySelectorAll('ul.cs-select li)抓取元素并将类更改为与所单击的索引不匹配时选择的ListItem.这在某种程度上有效.但是,在几次单击之后,组件的状态尚未由React更新(仅由客户端JS),并且事情开始崩溃.我想要做的是更改this.state.isSelected兄弟列表项,并使用此状态刷新SelectableList组件.任何人都可以提供一个比我下面写的更好的替代品吗?
var React = require('react');
var SelectBox = require('./select-box');
var ListItem = React.createClass({
getInitialState: function() {
return {
isSelected: false
};
},
toggleSelected: function () {
if (this.state.isSelected == true) {
this.setState({
isSelected: false
})
} else {
this.setState({
isSelected: true
})
}
},
handleClick: function(listItem) {
this.toggleSelected();
this.props.onListItemChange(listItem.props.value);
var unboundForEach = Array.prototype.forEach,
forEach = Function.prototype.call.bind(unboundForEach);
forEach(document.querySelectorAll('ul.cs-select li'), function (el) {
// below is trying to
// make sure that when a user clicks on a list
// item in the SelectableList, then all the *other*
// list items get class="selected" removed.
// this works for the first time that you move through the
// list clicking the other items, but then, on the second
// pass through, starts to fail, requiring *two clicks* before the
// list item is selected again.
// maybe there's a better more "reactive" method of doing this?
if (el.dataset.index != listItem.props.index && el.classList.contains('selected') ) {
el.classList.remove('selected');
}
});
},
render: function() {
return (
<li ref={"listSel"+this.props.key}
data-value={this.props.value}
data-index={this.props.index}
className={this.state.isSelected == true ? 'selected' : '' }
onClick={this.handleClick.bind(null, this)}>
{this.props.content}
</li>
);
}
});
var SelectableList = React.createClass({
render: function() {
var listItems = this.props.options.map(function(opt, index) {
return <ListItem key={index} index={index}
value={opt.value} content={opt.label}
onListItemChange={this.props.onListItemChange.bind(null, index)} />;
}, this);
return <ul className="cs-select">{ listItems }</ul>;
}
})
var CustomSelect = React.createClass({
getInitialState: function () {
return {
selectedOption: ''
}
},
handleListItemChange: function(listIndex, listItem) {
this.setState({
selectedOption: listItem.props.value
})
},
render: function () {
var options = [{value:"One", label: "One"},{value:"Two", label: "Two"},{value:"Three", label: "Three"}];
return (
<div className="group">
<div className="cs-select">
<SelectableList options={options}
onListItemChange={this.handleListItemChange} />
<SelectBox className="cs-select"
initialValue={this.state.selectedOption}
fieldName="custom-select" options={options}/>
</div>
</div>
)
}
})
module.exports = CustomSelect;
Run Code Online (Sandbox Code Playgroud)
Col*_*say 24
父组件应该将回调传递给子组件,并且每个子组件在其状态更改时将触发该回调.您实际上可以将父级中的所有状态保存为单点,并将"选定"值作为道具传递给每个子项.
在这种情况下,孩子可能看起来像这样:
var Child = React.createClass({
onToggle: function() {
this.props.onToggle(this.props.id, !this.props.selected);
},
render: function() {
return <button onClick={this.onToggle}>Toggle {this.props.label} - {this.props.selected ? 'Selected!' : ''}!</button>;
}
});
Run Code Online (Sandbox Code Playgroud)
它没有状态,它只是onToggle在点击时触发回调.父母看起来像这样:
var Parent = React.createClass({
getInitialState: function() {
return {
selections: []
};
},
onChildToggle: function(id, selected) {
var selections = this.state.selections;
selections[id] = selected;
this.setState({
selections: selections
});
},
buildChildren: function(dataItem) {
return <Child
id={dataItem.id}
label={dataItem.label}
selected={this.state.selections[dataItem.id]}
onToggle={this.onChildToggle} />
},
render: function() {
return <div>{this.props.data.map(this.buildChildren)}</div>
}
});
Run Code Online (Sandbox Code Playgroud)
它包含状态中的一系列选择,当它处理来自子进程的回调时,它setState通过将其状态向下传递selected给每个子进程来重新呈现子进程.
你可以在这里看到一个有效的例子:
https://jsfiddle.net/fth25erj/
| 归档时间: |
|
| 查看次数: |
21532 次 |
| 最近记录: |