1
votes

I am trying to render a list of items with react js. Since my list items relatively complicated I have created a simple fiddle to state my problem.

fiddle

In my case I have an infinite scroll of posts and increasing render time with each push of posts going out of reasonable render times really quick. it starts with 200-250 ms and goes up to 500ms after like 10 pushes (each push has 0-10 posts).

How can I fix the render time of newly added items? or is it just how the react js work.

Here is my main ReactComponent simplified.

React.createClass({
    shouldComponentUpdate: function (nextProps, nextState) {
        return nextState.posts.length !== this.state.posts.length;
    },
    getInitialState: function () {
        return {
            posts: []
        };
    },
    // getStream is bound to a scroll event handler. Simply, this function is called when user gets close to the end of page.
    getStream: function () {
        var self = this;
        ... ajax call success: (jsonResult) ...
        self.setState({
            posts: React.addons.update(self.state.posts, { $push: jsonResult })
        });
        ... end ....
    },
    render: function () {
        var self = this;

        var postNode = this.state.posts.map(function (post, i) {
            if (post.isActivity) {
                return (<ReactActivity key={i}></ReactActivity>);
            }
            else {
                return (<ReactStreamPost key={i}></ReactStreamPost>);
            }
        });

        return (<div>
            {postNode}
        </div>);
    }
    });

And ReactStreamPost and ReactStreamActivity can be stateless components at this point. like

var ReactStreamPost = React.createClass({
    shouldComponentUpdate: function () {
        return false;
    },
    render: function () {
        return (
            <div className="stream-post">
                <div className="post-topbar">
                    <a href="#" className="display-name">Test USER</a>
                </div>

                <div className="post-inner-wrapper">
                    <div className="post-owner-big">
                        <div className="post-owner">
                            <img className="profile-img" />
                        </div>
                    </div>
                    <div className="post-content">
                        <div className="post-header">
                            <div className="post-owner">
                                <img className="profile-img" />
                            </div>
                            <div className="post-agt">
                                <ReactAutoGenerateTitle></ReactAutoGenerateTitle>
                            </div>
                        </div>
                        <div className="post-title">
                            <div>
                                <a href="#" className="display-name">Test USER</a><span> Post title</span>
                            </div>
                        </div>
                        <div className="attachments">
                            attachments
                        </div>

                        <div className="post-actions">
                            <div className="left-actions">
                                <a href="#">
                                    <i className="icon icon-add-info"></i><span>Add info</span>
                                </a>
                            </div>
                            <div className="right-actions">
                                <a href="#" className="toggler">
                                    <i className="icon"></i>
                                    <span>x</span>
                                </a>
                                <a href="#" className="toggler">
                                    <i className="icon"></i>
                                    <span>x</span>
                                </a>
                                <a href="#" className="share icon icon-share"></a>
                            </div>
                        </div>

                        <div className="post-comments">
                            <div className="comment-block">
                                <div className="commentor">
                                    <img />
                                </div>
                                <div className="comment">
                                    <a href="#">Test USER</a><span>: </span><span>Comment test</span>
                                </div>
                                <div className="comment-date">
                                    <span>comment date</span>
                                </div>
                            </div>

                            <div className="comment-form">
                                <div className="commentor">
                                    <img />
                                </div>
                                <div className="text-area">
                                    <textarea rows="1" className="small"></textarea>
                                </div>
                                <div className="submit-comment">
                                    <a href="#" className="icon icon-send"></a>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                <div className="post-date">
                    <span>post date</span>
                </div>
            </div>
        );
    }
});
1
You're adding more DOM elements of course time would increase.Henrik Andersson
But each time I add same number of elements to dom. I know react re renders on each state update, but this costs seemed abit high to me.Azadrum
Please don't use array indices as child element keys. You'll get much better performance if you use a key that won't change when something else is added to the list.rossipedia

1 Answers

3
votes

This is because every time you add more elements, the whole list is re-rendered, and that also includes the list items that were already rendered before.

One way to fix is to put the list item in it's own component and use shouldComponentUpdate to not re-render it. This will still increase the time, as it still needs to check whether it needs to re-render or not, but the inxcrease won't be that steep. A working fiddle here. Your row component will look like this:-

  var Row = React.createClass({
  shouldComponentUpdate: function() {
    return false;
  },

  render: function() {
    return ( < li > < span > some < /span><span>more</span > < span > elements < /span></li > )
  }
})