我试图使用 ReactCSSTransitionGroup 为列表插入和删除设置动画,但删除动画始终只为列表的最后一个项目设置动画,而不是为正在删除的项目设置动画。
这里有一个 jsbin 来说明这个问题。尝试按“添加”按钮以验证插入动画确实按预期工作,然后单击任何项目旁边的“x”以查看问题,其中列表的最后一个项目是动画而不是您试图删除的项目。
我在设置 TransitionGroup 时做错了什么还是我在 CSS 转换定义中遗漏了什么?
我试图使用 ReactCSSTransitionGroup 为列表插入和删除设置动画,但删除动画始终只为列表的最后一个项目设置动画,而不是为正在删除的项目设置动画。
这里有一个 jsbin 来说明这个问题。尝试按“添加”按钮以验证插入动画确实按预期工作,然后单击任何项目旁边的“x”以查看问题,其中列表的最后一个项目是动画而不是您试图删除的项目。
我在设置 TransitionGroup 时做错了什么还是我在 CSS 转换定义中遗漏了什么?
您遇到此问题是因为您将其index
用作密钥:
let nodes = items.map((item, index) => {
let idx = index
return (<Item key={index} value={item} index={index} _delete={this._onDelete}/>)
})
Reactkey
在虚拟 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>
然后想象您删除了 index 处的元素2
。您现在拥有以下数组和以下 DOM 结构:
const arr = [2, 4, 8];
<li key={0}>2</li>
<li key={1}>4</li>
<li key={2}>8</li>
请注意,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}/>)
})
// ...
}
}