我正在尝试使用React交换一个元素的两个孩子。
<div style={{position: 'relative'}}>
{this.state.items.map((item, index) => (
<div
key={item}
style={{position: 'absolute',
transform: `translateY(${index * 20}px)`,
transition: '1s linear transform'}}>
{item}
</div>
))}
</div>
state.items
是两个项目的数组。重新排序时,两个孩子div
应该过渡到新的位置。
现实情况是,当第二个元素按预期过渡时,第一个元素立即跳了起来。
据我所知,React认为它可以重用一个子元素,但不能重用其他子元素,尽管文档说如果我们使用该key
属性,它应该始终重用元素:https : //facebook.github.io /react/docs/reconciliation.html(至少,我是这样理解的)。
我应该在代码中进行哪些更改以使其按预期工作?还是React中的错误?
警告:我在这个答案中做一些假设,尽管如此,它仍然可以反映出您(以前是我的)一些问题。同样,我的解决方案几乎可以肯定得到简化,但是出于回答这个问题的目的,它应该足够了。
这是一个很好的问题。打开开发工具并查看交换项目时实际发生的事情,我感到有些惊讶。
如果你看一看,你可以有点明白作出反应达到。第二个元素根本不更改其样式属性,仅交换内部文本节点,而第一个元素作为新元素放入dom中。
如果我不得不猜测的话,这是因为交换数组中的两个项目的工作方式是,其中至少有一个项目被复制到temp变量中,然后又放回到数组中。
我以为,如果您随机进行翻译,则两个元素都会获得新的风格道具和动画效果,但这只是更清楚地表明了这不是预期的行为。
在寻找解决方案的途中:
作为实验,如果我们提前创建节点,然后将索引prop传递到render中,该怎么办React.cloneElement
?在此过程中,让我们呈现一个span
ifindex === 0
和div
else。无需担心任何按键。
http://codepen.io/alex-wilmer/pen/pbaXzQ?editors=1010
现在打开开发工具可以准确地说明React的意图。React正在保留元素,仅更改相关部分,在这种情况下,是innerText节点和元素类型。因为样式正好按1:1交换,所以不需要样式更新。
解决方案:
您可以提前生成React元素,将其保留在数组中,这样就没有键可以改组并弄清楚如何放回DOM中。然后使用另一个数组来跟踪预期的顺序。可能极度令人费解,但它可行!
http://codepen.io/alex-wilmer/pen/kXZKoN?editors=1010
const Item = function (props) {
return (
<div
style={{position: 'absolute',
transform: `translateY(${props.index * 20}px)`,
transition: '0.5s linear transform'}}>
{props.children}
</div>
)
}
const App = React.createClass({
getInitialState () {
return {
items: [
{item: 'One', C: <Item>One</Item>},
{item: 'Two', C: <Item>Two</Item>}
],
order: ['One', 'Two']
};
},
swap () {
this.setState({
order: [this.state.order[1], this.state.order[0]]
});
},
render: function () {
return <div>
<button onClick={this.swap}>Swap</button>
<div style={{position: 'relative'}}>
{this.state.items.map(x =>
React.cloneElement(x.C, {
index: this.state.order.findIndex(z => z === x.item)
}))
}
</div>
</div>;
}
});
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句