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>;
}