7

I'm building an app with React and Reflux, and I am trying to render a list of items in a specific order.

The items are custom Post components that are rendered in reverse chronological order, so the newest post is at the top of the list.

I am using Khan Academy's TimeoutTransitionGroup to have the list items fade in and out.

The problem I'm seeing is that when I add a new post and the component gets the updated list via new props, the transition happens on the last element in the list rather than the first. I would like to have it so that the first element fades in, since that's the position of the new item that was added.


Post 2 <- This post was newly added


Post 1 <- This post fades in


Is there a way to specify the same order of items, but render them in the reverse order, or something similar?

This is my component's render function:

    if (!(this.props.posts && this.props.ordering)) return false;
    var posts = this.props.ordering.map(function(postId, index) {
        return <Post key={index} post={this.props.posts[postId]}/>;
    }, this);
    return (
        <div className="post-collection">
            <TimeoutTransitionGroup 
                enterTimeout={500}
                leaveTimeout={500}  
                transitionName="postTransition">
                {posts}
            </TimeoutTransitionGroup>
        </div>
    );

This is the CSS transition:

.postTransition-enter {
    opacity: 0;
    transition: opacity .25s ease-in;
}

.postTransition-enter.postTransition-enter-active {
    opacity: 1;
}

.postTransition-leave {
    opacity: 1;
    transition: opacity .25s ease-in;
}

.postTransition-leave.postTransition-leave-active {
    opacity: 0;
}

Any help will be much appreciated!

JasonMArcher
  • 14,195
  • 22
  • 56
  • 52
hedgeday
  • 93
  • 1
  • 1
  • 6

2 Answers2

18

You shouldn't use index as key, it defeats the purpose. For example, if you add an item to the beginning of the array, react will detect only one new key - the last one. All other components would be reconciled according to their keys. You should use unique id of a post as a key instead.

vkurchatkin
  • 13,364
  • 2
  • 47
  • 55
  • 1
    Changing the key worked perfectly. It's so obvious now that you pointed it out. Thanks! – hedgeday May 04 '15 at 01:06
  • This is one of the trickiest parts of getting started with the ReactCSSTransitionGroup because React usually only complains about the `key` attribute when its just not there on elements/components that you're generating in a loop... since it doesn't complain for cases where the items are rerendered but their `keys` stay the same, this is much harder to figure out what is going on. Great answer! – Jason Frank Feb 17 '16 at 19:43
  • damn! this indeed solved my problem. Thanks for the tip about not using the index as the component `key` – Mauricio Soares Apr 04 '16 at 19:05
  • I always find using a string as an indicator plus a `Math.random()` the most useful for generating unique keys when there is no unique id to work with. – Amin Jafari Oct 06 '17 at 18:02
4

I had a similar issue but it seemed the op had an initial issue of how to properly utilize key in react. With that said this worked for reversing the ordering from ascending to descending.

var NotesList = React.createClass({
render: function () {
    var notes = this.props.notepad.notes;

    return (
        <div className="note-list">
            {
                notes.reverse().map(function (note) {
                    return (
                        <NoteSummary key={note.id} note={note}/>
                    );
                })
            }
        </div>
    );
}
});
Christian Matthew
  • 4,014
  • 4
  • 33
  • 43
  • 14
    this will modify the original array you should use [...notes].reverse() – Fareed Alnamrouti Dec 20 '16 at 13:36
  • @fareednamrouti can you explain what is wrong with modifying the original array? What is the complete syntax and I will adjust it. Thanks. – Christian Matthew Apr 22 '17 at 19:03
  • modifying the original data will lead to many problems: 1- this will prevent the component from knowing if this property has changed or not so it might not re-render itself again 2- every time your component render it will reverse the array again, I suggest you read more about Functional Programming and Redux – Fareed Alnamrouti Apr 23 '17 at 03:12
  • I don't remember if this is my exact implementation but it works as expected. Again, I am not seeing what you posted i.e. [notes].reverse()... and what I posted... I guess that is the confusion – Christian Matthew Apr 24 '17 at 07:58
  • 1
    [...notes] will just copy the array you can also use notes.concat(), the reverse function of the array will modify the original array and it's not right thing todo – Fareed Alnamrouti Apr 24 '17 at 08:13
  • @ChristianMatthew if you modify the original array and save it then request it back your array will save in reverse. And you will keep reversing it if you make changes. Making your array flip flop. – mjwrazor Aug 28 '17 at 14:30
  • @mjwrazor you're saying save... there is not a save going on here. this is referring to what is on screen to the end user – Christian Matthew Aug 30 '17 at 20:20
  • @ChristianMatthew I am speaking theoretically. Another example, If you have this component nested and it lets say gets updated, then it reverses, and if it gets updated again then it reverses again, flipping. – mjwrazor Aug 31 '17 at 13:42