Как мне легко установить состояние родственных компонентов в React?
У меня есть начало интерактивного компонента списка, который будет служить для выбора элемента. Как вы можете видеть из приведенного ниже,onClick
изListItem
Я передаю состояние дочернего элемента (ListItem
в данном случае) родителям (SelectableList
, а такжеCustomSelect
составная часть). Это работает нормально. Тем не менее, то, что я также хотел бы сделать, это изменить состояниеродной брат компоненты (другие ListItems), чтобы я мог переключать их выбранные состояния при нажатии на один из ListItems.
На данный момент я просто использую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;