Javascript 反应:在列表洗牌的连续渲染上会发生什么?
我正在尝试创建一个列表,其中随机地播放一些动画 这里是我使用Javascript 反应:在列表洗牌的连续渲染上会发生什么?,javascript,html,css-animations,reactjs,Javascript,Html,Css Animations,Reactjs,我正在尝试创建一个列表,其中随机地播放一些动画 这里是我使用键道具识别每个孩子的地方 var ListAnimate=React.createClass({ 名单:[ {id:1,标题:“你好”}, {id:2,标题:“那里”}, {id:3,标题:“Whatsup”}, {id:4,标题:“Sanket”}, {id:5,标题:“萨胡”}, ], shuffle:function(){ this.list.shuffle();//洗牌数组! 这个.forceUpdate(); }, rend
键
道具识别每个孩子的地方
var ListAnimate=React.createClass({
名单:[
{id:1,标题:“你好”},
{id:2,标题:“那里”},
{id:3,标题:“Whatsup”},
{id:4,标题:“Sanket”},
{id:5,标题:“萨胡”},
],
shuffle:function(){
this.list.shuffle();//洗牌数组!
这个.forceUpdate();
},
render:function(){
返回
洗牌
{this.list.map(函数(el,i){
return- {el.caption}{el.id}
;
})}
;
}
});
React.render(,document.body);
从中,它声明在连续渲染期间使用键
道具来标识数组中的元素。因此,刚刚重新排序的项目不能卸载并装载到新位置,而应该重新定位它们,但这种情况似乎不会发生在小提琴中,列表顶部的节点总是卸载并装载到不同的位置
但是底部的元素似乎与动画配合得很好。我创建了一个小提琴来显示
li
元素实际上没有被装载/卸载
我已将li
元素转换为MyLi
元素,并在调用componentDidMount
和componentWillUnmount
函数时记录消息。只有componentDidMount
回调在第一次渲染期间被调用,而洗牌后不会调用任何回调:
var MyLi = React.createClass({
componentDidMount : function(){
console.log("MyLi component did mount.");
},
componentWillUnmount : function(){
console.log("MyLi component will unmount.");
},
render : function(){
return <li {...this.props}>{this.props.children}</li>
}
});
var ListAnimate = React.createClass({
list: [
{id: 1, caption: "Hello"},
{id: 2, caption: "There"},
{id: 3, caption: "Whatsup"},
{id: 4, caption: "Sanket"},
{id: 5, caption: "Sahu"},
],
shuffle: function() {
this.list.shuffle();
this.forceUpdate();
},
render: function() {
return <div>
<button onClick={this.shuffle}>Shuffle</button>
<ul>
{this.list.map(function(el, i){
return <MyLi key={el.id} style={ {top: (i*60)+'px'} }>{el.caption} {el.id}</MyLi>;
})}
</ul>
</div>;
}
});
window.React = React;
React.render(<ListAnimate />, document.body);
Array.prototype.shuffle = function() {
var i = this.length, j, temp;
if ( i == 0 ) return this;
while ( --i ) {
j = Math.floor( Math.random() * ( i + 1 ) );
temp = this[i];
this[i] = this[j];
this[j] = temp;
}
return this;
}
var MyLi=React.createClass({
componentDidMount:function(){
log(“MyLi组件确实挂载了”);
},
componentWillUnmount:function(){
log(“MyLi组件将卸载”);
},
render:function(){
return{this.props.children}
}
});
var ListAnimate=React.createClass({
名单:[
{id:1,标题:“你好”},
{id:2,标题:“那里”},
{id:3,标题:“Whatsup”},
{id:4,标题:“Sanket”},
{id:5,标题:“萨胡”},
],
shuffle:function(){
this.list.shuffle();
这个.forceUpdate();
},
render:function(){
返回
洗牌
{this.list.map(函数(el,i){
返回{el.caption}{el.id};
})}
;
}
});
window.React=反应;
React.render(,document.body);
Array.prototype.shuffle=函数(){
var i=该长度,j,温度;
如果(i==0)返回该值;
而(--i){
j=数学地板(数学随机()*(i+1));
温度=此[i];
这个[i]=这个[j];
此[j]=温度;
}
归还这个;
}
请记住,对于要查找的动画类型,您需要始终保持DOM的顺序不变,并且只更新它们在组件渲染函数中的位置
我用这个策略修改了你的第一把小提琴:
render:function(){
//创建列表的排序版本以呈现DOM
var sortedCopy=this.state.list.slice().sort(函数(a,b){
返回a.id-b.id;
});
返回
洗牌
{sortedCopy.map(函数(el,i){
//在无序列表中查找元素的位置
//它给出了元素必须处于的位置
var pos=此.state.list.indexOf(el);
return-
{el.caption}{el.id}
;
},这个)}
;
}
仍有改进的余地,但我将留给您。完成更改后,您需要单击小提琴中的“叉子”。这个链接只是指向hello world小提琴。此外,您还需要在问题中包含来自您的小提琴的代码,以防JSFIDLE消失。对不起,现在就更新它!(y) 很好的调试,但定位有什么问题?这不是CSS问题,我检查了Inspector Elements面板。我认为React会重新排序实际的DOM元素(它不会丢弃现有的DOM元素和React类实例并创建新的),并更新它们的
top
样式属性。如果它重新排序现有的DOM,那个么为什么只有那个些从下到上移动的元素在制作动画,而不能从上到下使用这些元素呢?在Google Chrome的调试器中,如果向下移动,它将丢失元素面板中的选定元素,但上升的元素仍保留选定元素。我明白你的意思。我不能给出一个权威的答案,但我认为如果重新排序算法是这样的话是有意义的。“从下到上移动元素以完成给定的排序。”但可能比这更复杂。目前,重新排序并不总是有效的,主要是一个实现细节。有一个问题,我现在似乎找不到,但它更详细地解释了情况。如果你找到了,评论一下,让他们知道这对你很重要。谢谢你详细的回答和提琴!这很有效,但我的解决方案也应该有效。看起来React的渲染函数有问题(如另一个答案的注释中所述),您读过这篇关于React算法的文章吗?在最后一节中,“[…]您可以表达这样一个事实,即一个子树已在其同级之间移动,但您无法判断它已移动到其他地方。”谢谢!您帮助我解决了复制JS数组时遇到的另一个问题,.slice()
是我在this.state.lis中需要的关键部分
var MyLi = React.createClass({
componentDidMount : function(){
console.log("MyLi component did mount.");
},
componentWillUnmount : function(){
console.log("MyLi component will unmount.");
},
render : function(){
return <li {...this.props}>{this.props.children}</li>
}
});
var ListAnimate = React.createClass({
list: [
{id: 1, caption: "Hello"},
{id: 2, caption: "There"},
{id: 3, caption: "Whatsup"},
{id: 4, caption: "Sanket"},
{id: 5, caption: "Sahu"},
],
shuffle: function() {
this.list.shuffle();
this.forceUpdate();
},
render: function() {
return <div>
<button onClick={this.shuffle}>Shuffle</button>
<ul>
{this.list.map(function(el, i){
return <MyLi key={el.id} style={ {top: (i*60)+'px'} }>{el.caption} {el.id}</MyLi>;
})}
</ul>
</div>;
}
});
window.React = React;
React.render(<ListAnimate />, document.body);
Array.prototype.shuffle = function() {
var i = this.length, j, temp;
if ( i == 0 ) return this;
while ( --i ) {
j = Math.floor( Math.random() * ( i + 1 ) );
temp = this[i];
this[i] = this[j];
this[j] = temp;
}
return this;
}
render: function() {
// create a sorted version of the list to render the DOM
var sortedCopy = this.state.list.slice().sort(function(a, b) {
return a.id - b.id;
});
return <div>
<button onClick={this.shuffle}>Shuffle</button>
<ul>
{sortedCopy.map(function(el, i) {
// find the position of the element in the shuffled list
// which gives the position the element must be
var pos = this.state.list.indexOf(el);
return <li key={el.id} style={ {top: (pos*60)+'px'} }>
{el.caption} {el.id}
</li>;
}, this)}
</ul>
</div>;
}