Reactjs 如何在React中轻松设置同级组件的状态?
我已经有了一个可点击列表组件的开始,它将用于驱动一个select元素。从下面可以看到,Reactjs 如何在React中轻松设置同级组件的状态?,reactjs,siblings,Reactjs,Siblings,我已经有了一个可点击列表组件的开始,它将用于驱动一个select元素。从下面可以看到,onClickListItem,我将子元素的状态(ListItem,在本例中)传递给父元素(SelectableList,以及CustomSelect组件)。这很好用。但是,我还想做的是更改同级组件(其他ListItems)的状态,以便在单击其中一个ListItems时切换其选定状态 目前,我只是使用document.querySelectorAll('ul.cs-select li)获取元素,并在类与单击的列
onClickListItem
,我将子元素的状态(ListItem
,在本例中)传递给父元素(SelectableList
,以及CustomSelect
组件)。这很好用。但是,我还想做的是更改同级组件(其他ListItems)的状态,以便在单击其中一个ListItems时切换其选定状态
目前,我只是使用document.querySelectorAll('ul.cs-select li)
获取元素,并在类与单击的列表项的索引不匹配时将其更改为selected。这在一定程度上是可行的。但是,单击几下之后,组件的状态并没有被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;
var React=require('React');
var SelectBox=require(“./SelectBox”);
var ListItem=React.createClass({
getInitialState:函数(){
返回{
结果:错
};
},
toggleSelected:函数(){
if(this.state.isSelected==true){
这是我的国家({
结果:错
})
}否则{
这是我的国家({
是的
})
}
},
handleClick:函数(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'),函数(el){
//下面是试图
//确保当用户单击列表时
//可选择列表中的项目,然后是所有*其他*
//删除列表项get class=“selected”。
//这是您第一次通过
//单击列表中的其他项目,然后在第二个
//通过,开始失败,需要在
//再次选择列表项。
//也许有更好的更“被动”的方法?
如果(el.dataset.index!=listItem.props.index&&el.classList.contains('selected')){
el.classList.remove('selected');
}
});
},
render:function(){
返回(
{this.props.content}
);
}
});
var SelectableList=React.createClass({
render:function(){
var listItems=this.props.options.map(函数(opt,索引){
返回;
},这个);
return{listItems}
;
}
})
var CustomSelect=React.createClass({
getInitialState:函数(){
返回{
已选择选项:“”
}
},
handleListItemChange:函数(listIndex、listItem){
这是我的国家({
selectedOption:listItem.props.value
})
},
渲染:函数(){
var选项=[{value:“One”,label:“One”},{value:“Two”,label:“Two”},{value:“Three”,label:“Three”}];
返回(
)
}
})
module.exports=CustomSelect;
父组件应该将回调传递给子组件,并且每个子组件在其状态更改时都会触发该回调。实际上,您可以在父对象中保留所有状态,将其用作单个真理点,并将“选定”值作为道具传递给每个子对象
在这种情况下,孩子可能看起来像这样:
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>;
}
});
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>
}
});
它在状态中保存一个选择数组,当它处理来自子对象的回调时,它使用setState
通过在selected
prop中将其状态向下传递给每个子对象来重新渲染子对象
您可以在此处看到一个工作示例:
以下代码帮助我设置两个兄弟姐妹之间的通信。在render()和componentDidMount()调用期间,在其父级中完成设置
类应用程序扩展了React.Component{
专用导航面板:导航面板;
private_mapPanel:mapPanel;
构造函数(){
超级();
this.state={};
}
//ReactJS在`render()之后调用`componentDidMount()``
componentDidMount(){
//将地图面板传递到导航面板
//它将允许_navigationPanel直接调用_mapPanel
this.\u navigationPanel.setMapPanel(this.\u mapPanel);
}
render(){
返回(
//`ref=`有助于在渲染期间获取对子对象的引用
{this._navigationPanel=child;}}/>
{this.\u mapPanel=child;}}/>
);
}
}
兄弟姐妹沟通的另一种策略是使用观察者模式
观察者模式是一种软件设计模式,其中一个对象可以向多个其他对象发送消息
使用此策略不需要兄弟姐妹关系或父子关系
在React的上下文中,这意味着一些组件订阅以接收特定消息,而其他组件将消息发布到这些订阅
class App extends React.Component<IAppProps, IAppState> {
private _navigationPanel: NavigationPanel;
private _mapPanel: MapPanel;
constructor() {
super();
this.state = {};
}
// `componentDidMount()` is called by ReactJS after `render()`
componentDidMount() {
// Pass _mapPanel to _navigationPanel
// It will allow _navigationPanel to call _mapPanel directly
this._navigationPanel.setMapPanel(this._mapPanel);
}
render() {
return (
<div id="appDiv" style={divStyle}>
// `ref=` helps to get reference to a child during rendering
<NavigationPanel ref={(child) => { this._navigationPanel = child; }} />
<MapPanel ref={(child) => { this._mapPanel = child; }} />
</div>
);
}
}