Big list performance with React
<p>I am in the process of implementing a filterable list with React. The structure of the list is as shown in the image below.</p>

<p><a href="https://i.stack.imgur.com/lTcZm.png" rel="noreferrer"><img src="https://i.stack.imgur.com/lTcZm.png" alt="enter image description here"></a></p>

<p><strong>PREMISE</strong></p>

<p>Here's a description of how it is supposed to work:</p>

<ul>
<li>The state resides in the highest level component, the <code>Search</code> component.</li>
<li>The state is described as follows:</li>
</ul>

<pre>
{
    visible : boolean,
    files : array,
    filtered : array,
    query : string,
    currentlySelectedIndex : integer
}
</pre>

<ul>
<li><code>files</code> is a potentially very large, array containing file paths (10000 entries is a plausible number).</li>
<li><code>filtered</code> is the filtered array after the user types at least 2 characters. I know it's derivative data and as such an argument could be made about storing it in the state but it is needed for</li>
<li><p><code>currentlySelectedIndex</code> which is the index of the currently selected element from the filtered list.</p></li>
<li><p>User types more than 2 letters into the <code>Input</code> component, the array is filtered and for each entry in the filtered array a <code>Result</code> component is rendered</p></li>
<li><p>Each <code>Result</code> component is displaying the full path that partially matched the query, and the partial match part of the path is highlighted. For example the DOM of a Result component, if the user had typed 'le' would be something like this :</p>

<p><code>&lt;li&gt;this/is/a/fi&lt;strong&gt;le&lt;/strong&gt;/path&lt;/li&gt;</code></p></li>
<li>If the user presses the up or down keys while the <code>Input</code> component is focused the <code>currentlySelectedIndex</code> changes based on the <code>filtered</code> array. This causes the <code>Result</code> component that matches the index to be marked as selected causing a re-render</li>
</ul>

<p><strong>PROBLEM</strong></p>

<p>Initially I tested this with a small enough array of <code>files</code>, using the development version of React, and all worked fine. </p>

<p>The problem appeared when I had to deal with a <code>files</code> array as big as 10000 entries. Typing 2 letters in the Input would generate a big list and when I pressed the up and down keys to navigate it it would be very laggy.</p>

<p>At first I did not have a defined component for the <code>Result</code> elements and I was merely making the list on the fly, on each render of the <code>Search</code> component, as such:</p>

<pre><code>results  = this.state.filtered.map(function(file, index) {
    var start, end, matchIndex, match = this.state.query;

     matchIndex = file.indexOf(match);
     start = file.slice(0, matchIndex);
     end = file.slice(matchIndex + match.length);

     return (
         &lt;li onClick={this.handleListClick}
             data-path={file}
             className={(index === this.state.currentlySelected) ? "valid selected" : "valid"}
             key={file} &gt;
             {start}
             &lt;span className="marked"&gt;{match}&lt;/span&gt;
             {end}
         &lt;/li&gt;
     );
}.bind(this));
</code></pre>

<p>As you can tell, every time the <code>currentlySelectedIndex</code> changed, it would cause a re-render and the list would be re-created each time. I thought that since I had set a <code>key</code> value on each <code>li</code> element React would avoid re-rendering every other <code>li</code> element that did not have its <code>className</code> change, but apparently it wasn't so.</p>

<p>I ended up defining a class for the <code>Result</code> elements, where it explicitly checks whether each <code>Result</code> element should re-render based on whether it was previously selected and based on the current user input :</p>

<pre><code>var ResultItem = React.createClass({
    shouldComponentUpdate : function(nextProps) {
        if (nextProps.match !== this.props.match) {
            return true;
        } else {
            return (nextProps.selected !== this.props.selected);
        }
    },
    render : function() {
        return (
            &lt;li onClick={this.props.handleListClick}
                data-path={this.props.file}
                className={
                    (this.props.selected) ? "valid selected" : "valid"
                }
                key={this.props.file} &gt;
                {this.props.children}
            &lt;/li&gt;
        );
    }
});
</code></pre>

<p>And the list is now created as such: </p>

<pre><code>results = this.state.filtered.map(function(file, index) {
    var start, end, matchIndex, match = this.state.query, selected;

    matchIndex = file.indexOf(match);
    start = file.slice(0, matchIndex);
    end = file.slice(matchIndex + match.length);
    selected = (index === this.state.currentlySelected) ? true : false

    return (
        &lt;ResultItem handleClick={this.handleListClick}
            data-path={file}
            selected={selected}
            key={file}
            match={match} &gt;
            {start}
            &lt;span className="marked"&gt;{match}&lt;/span&gt;
            {end}
        &lt;/ResultItem&gt;
    );
}.bind(this));
}
</code></pre>

<p>This made performance <em>slightly</em> better, but it's still not good enough. Thing is when I tested on the production version of React things worked buttery smooth, no lag at all. </p>

<p><strong>BOTTOMLINE</strong></p>

<p><strong>Is such a noticeable discrepancy between development and production versions of React normal?</strong></p>

<p><strong>Am I understanding/doing something wrong when I think about how React manages the list?</strong> </p>

<p><strong>UPDATE 14-11-2016</strong></p>

<p>I have found this presentation of Michael Jackson, where he tackles an issue very similar to this one: <a href="https://youtu.be/7S8v8jfLb1Q?t=26m2s" rel="noreferrer">https://youtu.be/7S8v8jfLb1Q?t=26m2s</a></p>

<p>The solution is very similar to the one proposed by AskarovBeknar's <a href="https://stackoverflow.com/a/38193164/4651083">answer</a>, below</p>

<p><strong>UPDATE 14-4-2018</strong></p>

<p>Since this is apparently a popular question and things have progressed since the original question was asked, while I do encourage you to watch the video linked above, in order to get a grasp of a virtual layout, I also encourage you to use the <a href="https://github.com/bvaughn/react-virtualized" rel="noreferrer">React Virtualized</a> library if you do not want to re-invent the wheel. </p>