neurosnap
neurosnap

Reputation: 5798

React List Render Order Must Be Consistent?

I really don't know how to explain this problem, but I have the fiddles to help:

Only line 25 gets changed

CORRECT: http://jsfiddle.net/0maphg47/5/

var ListAnimate = React.createClass({
    getInitialState: function() {
        return {
            list: [
                {id: 1, caption: "Hello"},
                {id: 2, caption: "There"},
                {id: 3, caption: "Whatsup"},
                {id: 4, caption: "Sanket"},
                {id: 5, caption: "Sahu"}
            ]
        };
    },
    shuffle: function() {
        this.setState({ list: this.state.list.shuffle() });
    },
    render: function() {
        // create a sorted version of the list
        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
                    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>;
    }
});

React.render(<ListAnimate />, document.body);

WRONG: http://jsfiddle.net/0maphg47/6/

var ListAnimate = React.createClass({
    getInitialState: function() {
        return {
            list: [
                {id: 1, caption: "Hello"},
                {id: 2, caption: "There"},
                {id: 3, caption: "Whatsup"},
                {id: 4, caption: "Sanket"},
                {id: 5, caption: "Sahu"}
            ]
        };
    },
    shuffle: function() {
        this.setState({ list: this.state.list.shuffle() });
    },
    render: function() {
        // create a sorted version of the list
        var sortedCopy = this.state.list.slice().sort(function(a, b) {
            return a.id - b.id;
        });

        return <div>
            <button onClick={this.shuffle}>Shuffle</button>
            <ul>
                {this.state.list.map(function(el, i) {
                    // find the position of the element in the shuffled list
                    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>;
    }
});

React.render(<ListAnimate />, document.body);

Why do we have to render the li objects in the same order every time if the key can determine uniqueness? I don't get why the order of the li elements matter, but I'm probably missing something obvious

Upvotes: 1

Views: 385

Answers (1)

kes
kes

Reputation: 6167

Take a look in the Elements view of your browser's debugger to see what is happening to the DOM when you click on the Shuffle button.

In the first (correct) case, the only thing that changes in the DOM is the style attribute of each list item. The order and contents of the items don't change, only the appearance of the order changes. The element of key X was remains in the same position before and after the shuffle, so new DOM elements do not need to be created.

In the second (wrong) case, the actual order of the elements is shuffled. While key 1 may be in first position before the shuffle, it may in the fourth position after the shuffle. The attributes of the items are not being updated in place; rather, React may be creating new items where an item has changed positions. Hence, this can have an unpredictable effect on your transitions.

Upvotes: 1

Related Questions