use*_*412 14 css3 css-animations reactjs react-jsx
我试图使用ReactCSSTransitionGroup为列表插入和删除设置动画,但删除动画始终仅动画列表的最后一项而不是正在删除的项.
这是一个jsbin来说明这个问题.尝试按"添加"按钮以验证插入动画确实按预期工作,然后单击任何项目旁边的"x"以查看列表的最后一项是动画而不是您尝试删除的问题.
在设置TransitionGroup时我做错了什么,或者我在CSS转换定义中遗漏了什么?
Mic*_*ley 22
您遇到此问题是因为您使用的index
是您的密钥:
let nodes = items.map((item, index) => {
let idx = index
return (<Item key={index} value={item} index={index} _delete={this._onDelete}/>)
})
Run Code Online (Sandbox Code Playgroud)
React key
在虚拟DOM diffing期间使用该属性来确定删除了哪个元素,但索引永远不会充分满足此目的.
考虑这个例子:你从以下数组开始,这导致以下DOM结构:
const arr = [2, 4, 6, 8];
<li key={0}>2</li>
<li key={1}>4</li>
<li key={2}>6</li>
<li key={3}>8</li>
Run Code Online (Sandbox Code Playgroud)
然后想象你删除索引处的元素2
.您现在拥有以下数组和以下DOM结构:
const arr = [2, 4, 8];
<li key={0}>2</li>
<li key={1}>4</li>
<li key={2}>8</li>
Run Code Online (Sandbox Code Playgroud)
请注意,8
现在位于索引中2
; React看到这个DOM结构和最后一个结构之间的区别在于缺少li
with键3
,因此它将其删除.因此,无论您删除哪个数组元素,生成的DOM结构都将缺少li
with键3
.
解决方案是为列表中的每个项目使用唯一标识符; 在现实生活中,您可能需要使用id
字段或其他主键; 对于像这样的应用程序,您可以生成递增ID:
let id = 0;
class List extends Component {
constructor() {
this.state = {
items: [{id: ++id, value: 1}, {id: ++id, value: 2}]
}
// ...
}
_onClick(e) {
this.state.items.push({id: ++id, value: Math.round(Math.random() * 10)})
this.setState({items: this.state.items})
}
// ...
render() {
let items = this.state.items
let nodes = items.map((item, index) => {
let idx = index
return (<Item key={item.id} value={item.value} index={index} _delete={this._onDelete}/>)
})
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
工作示例:http://jsbin.com/higofuhuni/2/edit