当使用react-bootstrap的ModalTrigger和一系列项目时,我们遇到了一个奇怪的行为,因为当卸载父/所有者项目时它不会消失。我们怀疑这与React的虚拟DOM和差异机制,和/或我们自己滥用ModalTrigger有关。
设置很简单:内容反应组件具有保存项目名称数组的状态。它还有一个onClick(name)函数,它通过setState从数组中删除该名称。在渲染中,它使用_.map来创建一堆Item反应组件。
每个Item组件显示其名称和一个ModalTrigger,其中包含标有&#34的按钮;删除我"。点击按钮,它打开模态;点击"确定"在模态中,它执行内容删除功能的回调。
删除最后一项时,它可以正常工作:最后的Item组件已卸载,并使用它,ModalTrigger及其相应的模态。
我们看到的问题是删除除最后一项以外的任何项目。该项目被删除但模态保持打开,而我会天真地期望模态消失,因为父ModalTrigger消失了。不仅如此,当点击" ok"再次,列表中的下一个项目被删除,依此类推,直到模态恰好与最后一个项目相关联,此时点击" ok"最后会隐藏它。
我们的集体预感是,这是由overlayMixin的_overlayTarget是文档中的匿名元素引起的,因此不同的ModalTriggers不会区分它们。因此,当父级卸载并且React查找DOM差异时,它会看到之前的触发器并且说“嘿,这可能有效”#。
通过在Item的内部_onClick()函数中添加hide()调用可以很容易地解决整个问题,如代码中注释掉的那样,我们最终得出了我的问题:
我是否正确使用ModalTrigger,因为期望在父代卸载时它会消失?这就是我期望React一般工作的方式,这意味着react-bootstrap中的一个错误。
或者我应该明确地调用hide(),因为他们设计了这个组件的方式吗?
以下是一段重现此内容的代码。
谢谢!
var DeleteModal = React.createClass({
render:function() {
return (
<ReactBootstrap.Modal onRequestHide = {this.props.onRequestHide} title = "delete this?">
<div className="modal-body">
Are you sure?
</div>
<div className="modal-footer">
<button onClick={this.props.onOkClick}>ok</button>
<button onClick={this.props.onRequestHide}>cancel</button>
</div>
</ReactBootstrap.Modal>
);
}
});
var Item = React.createClass({
_onClick:function() {
//this.refs.theTrigger.hide();
this.props.onClick(this.props.name);
},
render:function() {
return (
<div>
<span>{this.props.name}</span>
<ModalTrigger modal={<DeleteModal onOkClick={this._onClick}/>} ref="theTrigger">
<button>delete me!</button>
</ModalTrigger>
</div>
);
}
});
var Content = React.createClass({
onClick:function(name) {
this.setState({items:_.reject(this.state.items, function(item) {return item === name;})});
},
getInitialState:function() {
return {items : ["first", "secondth", "thirdst"]};
},
render:function() {
return (
<div>
{_.map(this.state.items, function(item, i) {
return (
<Item name={item} onClick={this.onClick} key={i}/>
)}.bind(this)
)}
</div>
);
}
});
React.render(<Content/>, document.getElementById("mydiv"));
答案 0 :(得分:0)
原来这是对React&#34; key&#34;的误用。属性。我们为映射对象提供了整数键,所以当再次调用render时,会给出相同的初始键,这就是为什么React认为它应该重用相同的DOM元素。
如果相反我们给它key = {item}(其中item是一个简单的字符串)它在我们的例子中解决了它;然而,这引入了一个微妙的错误,如果有2个相同的字符串,React将只显示一个。
试图通过给它键来智取它= {item + i}引入了一个更微妙的错误,其中显示了重复的项目,但是大量删除,但在这种情况下,错误是在onClick方法中需要的修改为接受某种索引。
因此,我的要点是密钥必须是唯一的字符串,并且回调应该在执行任何修改时考虑这些密钥。