Javascript React 的大列表性能

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38033442/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 21:00:36  来源:igfitidea点击:

Big list performance with React

javascriptlistreactjs

提问by Dimitris Karagiannis

I am in the process of implementing a filterable list with React. The structure of the list is as shown in the image below.

我正在用 React 实现一个可过滤的列表。列表的结构如下图所示。

enter image description here

在此处输入图片说明

PREMISE

前提

Here's a description of how it is supposed to work:

以下是它应该如何工作的描述:

  • The state resides in the highest level component, the Searchcomponent.
  • The state is described as follows:
  • 状态驻留在最高级别的Search组件中。
  • 状态描述如下:
{
    visible : boolean,
    files : array,
    filtered : array,
    query : string,
    currentlySelectedIndex : integer
}
  • filesis a potentially very large, array containing file paths (10000 entries is a plausible number).
  • filteredis 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
  • currentlySelectedIndexwhich is the index of the currently selected element from the filtered list.

  • User types more than 2 letters into the Inputcomponent, the array is filtered and for each entry in the filtered array a Resultcomponent is rendered

  • Each Resultcomponent 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 :

    <li>this/is/a/fi<strong>le</strong>/path</li>

  • If the user presses the up or down keys while the Inputcomponent is focused the currentlySelectedIndexchanges based on the filteredarray. This causes the Resultcomponent that matches the index to be marked as selected causing a re-render
  • files是一个可能非常大的包含文件路径的数组(10000 个条目是一个合理的数字)。
  • filtered是用户键入至少 2 个字符后过滤后的数组。我知道它是派生数据,因此可以就将其存储在状态中提出这样的论点,但它是必需的
  • currentlySelectedIndex这是过滤列表中当前选定元素的索引。

  • 用户在Input组件中输入2 个以上的字母,数组被过滤,对于过滤数组中的每个条目,一个Result组件被呈现

  • 每个Result组件都显示与查询部分匹配的完整路径,并突出显示路径的部分匹配部分。例如 Result 组件的 DOM,如果用户输入了 'le' 将会是这样的:

    <li>this/is/a/fi<strong>le</strong>/path</li>

  • 如果用户在Input组件聚焦时按下向上或向下键,则currentlySelectedIndex基于filtered数组的更改。这会导致Result与索引匹配的组件被标记为选中,从而导致重新渲染

PROBLEM

问题

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

最初,我files使用 React 的开发版本,使用足够小的 数组进行了测试,并且一切正常。

The problem appeared when I had to deal with a filesarray 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.

当我不得不处理一个files有 10000 个条目的数组时,问题就出现了。在 Input 中输入 2 个字母会生成一个大列表,当我按下向上和向下键来导航时,它会非常滞后。

At first I did not have a defined component for the Resultelements and I was merely making the list on the fly, on each render of the Searchcomponent, as such:

起初我没有为Result元素定义一个组件,我只是在Search组件的每次渲染中即时制作列表,如下所示:

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 (
         <li onClick={this.handleListClick}
             data-path={file}
             className={(index === this.state.currentlySelected) ? "valid selected" : "valid"}
             key={file} >
             {start}
             <span className="marked">{match}</span>
             {end}
         </li>
     );
}.bind(this));

As you can tell, every time the currentlySelectedIndexchanged, it would cause a re-render and the list would be re-created each time. I thought that since I had set a keyvalue on each lielement React would avoid re-rendering every other lielement that did not have its classNamechange, but apparently it wasn't so.

如您所知,每次currentlySelectedIndex更改时,都会导致重新渲染,并且每次都会重新创建列表。我认为由于我为key每个li元素设置了一个值,React 会避免重新渲染所有其他li没有className改变的元素,但显然事实并非如此。

I ended up defining a class for the Resultelements, where it explicitly checks whether each Resultelement should re-render based on whether it was previously selected and based on the current user input :

我最终为Result元素定义了一个类,它明确地检查每个Result元素是否应该根据之前是否被选中以及当前用户输入重新渲染:

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 (
            <li onClick={this.props.handleListClick}
                data-path={this.props.file}
                className={
                    (this.props.selected) ? "valid selected" : "valid"
                }
                key={this.props.file} >
                {this.props.children}
            </li>
        );
    }
});

And the list is now created as such:

现在创建的列表如下:

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 (
        <ResultItem handleClick={this.handleListClick}
            data-path={file}
            selected={selected}
            key={file}
            match={match} >
            {start}
            <span className="marked">{match}</span>
            {end}
        </ResultItem>
    );
}.bind(this));
}

This made performance slightlybetter, 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.

这使性能稍微好一点,但仍然不够好。事情是当我在 React 的生产版本上进行测试时,一切都非常顺利,完全没有延迟。

BOTTOMLINE

底线

Is such a noticeable discrepancy between development and production versions of React normal?

React 的开发和生产版本之间存在如此明显的差异是否正常?

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

当我考虑 React 如何管理列表时,我是否理解/做错了什么?

UPDATE 14-11-2016

更新 14-11-2016

I have found this presentation of Michael Hymanson, where he tackles an issue very similar to this one: https://youtu.be/7S8v8jfLb1Q?t=26m2s

我找到了迈克尔Hyman逊的这个演讲,他在那里解决了一个与这个问题非常相似的问题:https: //youtu.be/7S8v8jfLb1Q?t=26m2s

The solution is very similar to the one proposed by AskarovBeknar's answer, below

该解决方案与下面AskarovBeknar 的回答提出的解决方案非常相似

UPDATE 14-4-2018

更新 14-4-2018

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 React Virtualizedlibrary if you do not want to re-invent the wheel.

由于这显然是一个受欢迎的问题,并且自从提出原始问题以来事情已经取得了进展,虽然我鼓励您观看上面链接的视频,为了掌握虚拟布局,我也鼓励您使用React Virtualized图书馆,如果你不想重新发明轮子。

采纳答案by deowk

As with many of the other answers to this question the main problem lies in the fact that rendering so many elements in the DOM whilst doing filtering and handling key events is going to be slow.

与这个问题的许多其他答案一样,主要问题在于在 DOM 中渲染如此多的元素同时进行过滤和处理关键事件会很慢。

You are not doing anything inherently wrong with regards to React that is causing the issue but like many of the issues that are performance related the UI can also take a big percentage of the blame.

对于导致问题的 React,您并没有做任何本质上的错误,但与许多与性能相关的问题一样,UI 也可以承担很大一部分责任。

If your UI is not designed with efficiency in mind even tools like React that are designed to be performant will suffer.

如果您的 UI 设计时没有考虑到效率,那么即使是像 React 这样被设计为高性能的工具也会受到影响。

Filtering the result set is a great start as mentioned by @Koen

正如@Koen 所说,过滤结果集是一个很好的开始

I've played around with the idea a bit and created an example app illustrating how I might start to tackle this kind of problem.

我对这个想法进行了一些尝试,并创建了一个示例应用程序,说明我可以如何开始解决此类问题。

This is by no means production readycode but it does illustrate the concept adequately and can be modified to be more robust, feel free to take a look at the code - I hope at the very least it gives you some ideas...;)

这绝不是production ready代码,但它确实充分说明了概念,并且可以修改为更健壮,请随意查看代码 - 我希望至少它能给你一些想法......;)

react-large-list-example

反应大列表示例

enter image description here

在此处输入图片说明

回答by Resonance

My experience with a very similar problem is that react really suffers if there are more than 100-200 or so components in the DOM at once. Even if you are super careful (by setting up all your keys and/or implementing a shouldComponentUpdatemethod) to only to change one or two components on a re-render, you're still going to be in a world of hurt.

我对一个非常相似的问题的经验是,如果 DOM 中同时有超过 100-200 个左右的组件,react 真的会受到影响。即使您非常小心(通过设置所有键和/或实现一个shouldComponentUpdate方法)只在重新渲染时更改一两个组件,您仍然会陷入困境。

The slow part of react at the moment is when it compares the difference between the virtual DOM and the real DOM. If you have thousands of components but only update a couple, it doesn't matter, react still has a massive difference operation to do between the DOMs.

目前 react 比较慢的部分是比较虚拟 DOM 和真实 DOM 的差异。如果你有数千个组件但只更新几个,没关系,react 在 DOM 之间仍然有巨大的差异操作要做。

When I write pages now I try to design them to minimise the number of components, one way to do this when rendering large lists of components is to... well... not render large lists of components.

当我现在编写页面时,我尝试设计它们以最小化组件的数量,在呈现大量组件列表时执行此操作的一种方法是......好吧......不呈现大量组件列表。

What I mean is: only render the components you can currently see, render more as you scroll down, you're user isn't likely to scroll down through thousands of components any way.... I hope.

我的意思是:只渲染你当前可以看到的组件,当你向下滚动时渲染更多,你的用户不太可能以任何方式向下滚动数千个组件......我希望。

A great library for doing this is:

一个伟大的图书馆这样做是:

https://www.npmjs.com/package/react-infinite-scroll

https://www.npmjs.com/package/react-infinite-scroll

With a great how-to here:

这里有一个很好的操作方法:

http://www.reactexamples.com/react-infinite-scroll/

http://www.reactexamples.com/react-infinite-scroll/

I'm afraid it doesn't remove components that are off the top of the page though, so if you scroll for long enough you're performance issues will start to reemerge.

恐怕它不会删除页面顶部的组件,所以如果你滚动足够长的时间,你的性能问题将开始重新出现。

I know it isn't good practice to provide a link as answer, but the examples they provide are going to explain how to use this library much better than I can here. Hopefully I have explained why big lists are bad, but also a work around.

我知道提供链接作为答案并不是一个好习惯,但是他们提供的示例将比我在这里更好地解释如何使用这个库。希望我已经解释了为什么大列表不好,但也是一种解决方法。

回答by Pierre Criulanscy

First of all, the difference between the development and production version of React is huge because in production there are many bypassed sanity checks (such as prop types verification).

首先,React 的开发和生产版本之间的差异是巨大的,因为在生产中存在许多绕过的健全性检查(例如 prop 类型验证)。

Then, I think you should reconsider using Redux because it would be extremely helpful here for what you need (or any kind of flux implementation). You should definitively take a look at this presentation : Big List High Performance React & Redux.

然后,我认为您应该重新考虑使用 Redux,因为它在这里对于您需要的(或任何类型的通量实现)非常有帮助。您绝对应该看看这个演示文稿:Big List High Performance React & Redux

But before diving into redux, you need to made some ajustements to your React code by splitting your components into smaller components because shouldComponentUpdatewill totally bypass the rendering of children, so it's a huge gain.

但是在深入研究 redux 之前,您需要通过将组件拆分为更小的组件来对您的 React 代码进行一些调整,因为这shouldComponentUpdate将完全绕过子组件的渲染,因此这是一个巨大的收获

When you have more granular components, you can handle the state with redux and react-redux to better organize the data flow.

当您有更细粒度的组件时,您可以使用 redux 和 react-redux 处理状态以更好地组织数据流。

I was recently facing a similar issue when I needed to render one thousand rows and be able to modify each row by editing its content. This mini app displays a list of concerts with potential duplicates concerts and I need to chose for each potential duplicate if I want to mark the potential duplicate as an original concert (not a duplicate) by checking the checkbox, and, if necessary, edit the name of the concert. If I do nothing for a particular potential duplicate item, it will be considered duplicate and will be deleted.

我最近遇到了类似的问题,当我需要渲染一千行并能够通过编辑其内容来修改每一行时。这个迷你应用程序显示了一个音乐会列表,其中包含潜在的重复音乐会,如果我想通过选中复选框将潜在的重复标记为原始音乐会(而不是重复),我需要为每个潜在的重复进行选择,并在必要时编辑演唱会名称。如果我对特定的潜在重复项不做任何处理,它将被视为重复项并将被删除。

Here is what it looks like :

这是它的样子:

enter image description here

在此处输入图片说明

There are basically 4 mains components (there is only one row here but it's for the sake of the example) :

基本上有 4 个电源组件(这里只有一行,但这是为了示例):

enter image description here

在此处输入图片说明

Here is the full code (working CodePen : Huge List with React & Redux) using redux, react-redux, immutable, reselectand recompose:

这是使用reduxreact-reduximmutablereselectrecompose的完整代码(工作 CodePen : Huge List with React & Redux):

const initialState = Immutable.fromJS({ /* See codepen, this is a HUGE list */ })

const types = {
    CONCERTS_DEDUP_NAME_CHANGED: 'diggger/concertsDeduplication/CONCERTS_DEDUP_NAME_CHANGED',
    CONCERTS_DEDUP_CONCERT_TOGGLED: 'diggger/concertsDeduplication/CONCERTS_DEDUP_CONCERT_TOGGLED',
};

const changeName = (pk, name) => ({
    type: types.CONCERTS_DEDUP_NAME_CHANGED,
    pk,
    name
});

const toggleConcert = (pk, toggled) => ({
    type: types.CONCERTS_DEDUP_CONCERT_TOGGLED,
    pk,
    toggled
});


const reducer = (state = initialState, action = {}) => {
    switch (action.type) {
        case types.CONCERTS_DEDUP_NAME_CHANGED:
            return state
                .updateIn(['names', String(action.pk)], () => action.name)
                .set('_state', 'not_saved');
        case types.CONCERTS_DEDUP_CONCERT_TOGGLED:
            return state
                .updateIn(['concerts', String(action.pk)], () => action.toggled)
                .set('_state', 'not_saved');
        default:
            return state;
    }
};

/* configureStore */
const store = Redux.createStore(
    reducer,
    initialState
);

/* SELECTORS */

const getDuplicatesGroups = (state) => state.get('duplicatesGroups');

const getDuplicateGroup = (state, name) => state.getIn(['duplicatesGroups', name]);

const getConcerts = (state) => state.get('concerts');

const getNames = (state) => state.get('names');

const getConcertName = (state, pk) => getNames(state).get(String(pk));

const isConcertOriginal = (state, pk) => getConcerts(state).get(String(pk));

const getGroupNames = reselect.createSelector(
    getDuplicatesGroups,
    (duplicates) => duplicates.flip().toList()
);

const makeGetConcertName = () => reselect.createSelector(
    getConcertName,
    (name) => name
);

const makeIsConcertOriginal = () => reselect.createSelector(
    isConcertOriginal,
    (original) => original
);

const makeGetDuplicateGroup = () => reselect.createSelector(
    getDuplicateGroup,
    (duplicates) => duplicates
);



/* COMPONENTS */

const DuplicatessTableRow = Recompose.onlyUpdateForKeys(['name'])(({ name }) => {
    return (
        <tr>
            <td>{name}</td>
            <DuplicatesRowColumn name={name}/>
        </tr>
    )
});

const PureToggle = Recompose.onlyUpdateForKeys(['toggled'])(({ toggled, ...otherProps }) => (
    <input type="checkbox" defaultChecked={toggled} {...otherProps}/>
));


/* CONTAINERS */

let DuplicatesTable = ({ groups }) => {

    return (
        <div>
            <table className="pure-table pure-table-bordered">
                <thead>
                    <tr>
                        <th>{'Concert'}</th>
                        <th>{'Duplicates'}</th>
                    </tr>
                </thead>
                <tbody>
                    {groups.map(name => (
                        <DuplicatesTableRow key={name} name={name} />
                    ))}
                </tbody>
            </table>
        </div>
    )

};

DuplicatesTable.propTypes = {
    groups: React.PropTypes.instanceOf(Immutable.List),
};

DuplicatesTable = ReactRedux.connect(
    (state) => ({
        groups: getGroupNames(state),
    })
)(DuplicatesTable);


let DuplicatesRowColumn = ({ duplicates }) => (
    <td>
        <ul>
            {duplicates.map(d => (
                <DuplicateItem
                    key={d}
                    pk={d}/>
            ))}
        </ul>
    </td>
);

DuplicatessRowColumn.propTypes = {
    duplicates: React.PropTypes.arrayOf(
        React.PropTypes.string
    )
};

const makeMapStateToProps1 = (_, { name }) => {
    const getDuplicateGroup = makeGetDuplicateGroup();
    return (state) => ({
        duplicates: getDuplicateGroup(state, name)
    });
};

DuplicatesRowColumn = ReactRedux.connect(makeMapStateToProps1)(DuplicatesRowColumn);


let DuplicateItem = ({ pk, name, toggled, onToggle, onNameChange }) => {
    return (
        <li>
            <table>
                <tbody>
                    <tr>
                        <td>{ toggled ? <input type="text" value={name} onChange={(e) => onNameChange(pk, e.target.value)}/> : name }</td>
                        <td>
                            <PureToggle toggled={toggled} onChange={(e) => onToggle(pk, e.target.checked)}/>
                        </td>
                    </tr>
                </tbody>
            </table>
        </li>
    )
}

const makeMapStateToProps2 = (_, { pk }) => {
    const getConcertName = makeGetConcertName();
    const isConcertOriginal = makeIsConcertOriginal();

    return (state) => ({
        name: getConcertName(state, pk),
        toggled: isConcertOriginal(state, pk)
    });
};

DuplicateItem = ReactRedux.connect(
    makeMapStateToProps2,
    (dispatch) => ({
        onNameChange(pk, name) {
            dispatch(changeName(pk, name));
        },
        onToggle(pk, toggled) {
            dispatch(toggleConcert(pk, toggled));
        }
    })
)(DuplicateItem);


const App = () => (
    <div style={{ maxWidth: '1200px', margin: 'auto' }}>
        <DuplicatesTable />
    </div>
)

ReactDOM.render(
    <ReactRedux.Provider store={store}>
        <App/>
    </ReactRedux.Provider>,
    document.getElementById('app')
);

Lessons learned by doing this mini app when working with huge dataset

在处理庞大的数据集时通过这个迷你应用程序获得的经验教训

  • React components work best when they are kept small
  • Reselect become very useful to avoid recomputation and keep the same reference object (when using immutable.js) given the same arguments.
  • Create connected component for component that are the closest of the data they need to avoid having component only passing down props that they do not use
  • Usage of fabric function to create mapDispatchToProps when you need only the initial prop given in ownPropsis necessary to avoid useless re-rendering
  • React & redux definitively rock together !
  • React 组件在保持较小时效果最佳
  • 重新选择对于避免重新计算并保持相同的引用对象(使用 immutable.js 时)给定相同的参数非常有用。
  • connect为最接近他们需要的数据的组件创建ed 组件,以避免组件只传递他们不使用的道具
  • 当您只需要给出的初始道具时,使用 fabric 函数创建 mapDispatchToPropsownProps是必要的,以避免无用的重新渲染
  • React 和 redux 绝对摇滚!

回答by AskarovBeknar

  1. React in development version checks for proptypes of each component to ease development process, while in production it is omitted.

  2. Filtering list of strings is very expensive operation for every keyup. it might cause performance issues because of single threaded nature of JavaScript. Solution might be to use debouncemethod to delay execution of your filter function until the delay is expired.

  3. Another problem might be the huge list itself. You can create virtual layoutand reuse created items just replacing data. Basically you create scrollable container component with fixed height, inside of which you will place list container. The height of list container should be set manually (itemHeight * numberOfItems) depending on the length of visible list, to have a scrollbar working. Then create a few item components so that they will fill scrollable containers height and maybe add extra one or two mimic continuous list effect. make them absolute position and on scroll just move their position so that it will mimic continuous list(I think you will find out how to implement it:)

  4. One more thing is writing to DOM is also expensive operation especially if you do it wrong. You can use canvas for displaying lists and create smooth experience on scroll. Checkout react-canvas components. I heard that they have already done some work on Lists.

  1. React 在开发版本中检查每个组件的 proptype 以简化开发过程,而在生产中它被省略。

  2. 过滤字符串列表对于每个 keyup 都是非常昂贵的操作。由于 JavaScript 的单线程特性,它可能会导致性能问题。解决方案可能是使用debounce方法延迟过滤器函数的执行,直到延迟到期。

  3. 另一个问题可能是庞大的列表本身。您可以创建虚拟布局并重用创建的项目,只需替换数据即可。基本上,您创建具有固定高度的可滚动容器组件,您将在其中放置列表容器。应根据可见列表的长度手动设置列表容器的高度 (itemHeight * numberOfItems),以使滚动条正常工作。然后创建一些项目组件,以便它们填充可滚动容器的高度,并可能添加额外的一两个模拟连续列表效果。使它们成为绝对位置并在滚动时移动它们的位置,以便它模仿连续列表(我想你会找到如何实现它的:)

  4. 另一件事是写入 DOM 也是一项昂贵的操作,尤其是如果你做错了。您可以使用画布来显示列表并在滚动时创建流畅的体验。签出反应画布组件。我听说他们已经在 Lists 上做了一些工作。

回答by Madbreaks

Check out React Virtualized Select, it's designed to address this issue and performs impressively in my experience. From the description:

查看 React Virtualized Select,它旨在解决这个问题,并且在我的经验中表现令人印象深刻。从描述来看:

HOC that uses react-virtualized and react-select to display large lists of options in a drop-down

使用 react-virtualized 和 react-select 在下拉列表中显示大量选项的 HOC

https://github.com/bvaughn/react-virtualized-select

https://github.com/bvaughn/react-virtualized-select

回答by Koen.

Like I mentioned in my comment, I doubt that users need all those 10000 results in the browser at once.

就像我在评论中提到的那样,我怀疑用户是否需要一次在浏览器中获得所有这 10000 个结果。

What if you page through the results, and always just show a list of 10 results.

如果您翻阅结果,并且始终只显示 10 个结果的列表,该怎么办?

I've created an exampleusing this technique, without using any other library like Redux. Currently only with keyboard navigation, but could easily be extended to work on scrolling as well.

我使用这种技术创建了一个示例,没有使用任何其他库,如 Redux。目前仅使用键盘导航,但也可以轻松扩展以进行滚动。

The example exists of 3 components, the container application, a search component and a list component. Almost all the logic has been moved to the container component.

该示例包含 3 个组件,容器应用程序、搜索组件和列表组件。几乎所有的逻辑都移到了容器组件中。

The gist lies in keeping track of the startand the selectedresult, and shifting those on keyboard interaction.

要点在于跟踪的startselected结果,并转移那些键盘交互。

nextResult: function() {
  var selected = this.state.selected + 1
  var start = this.state.start
  if(selected >= start + this.props.limit) {
    ++start
  }
  if(selected + start < this.state.results.length) {
    this.setState({selected: selected, start: start})
  }
},

prevResult: function() {
  var selected = this.state.selected - 1
  var start = this.state.start
  if(selected < start) {
    --start
  }
  if(selected + start >= 0) {
    this.setState({selected: selected, start: start})
  }
},

While simply passing all the files through a filter:

虽然只是通过过滤器传递所有文件:

updateResults: function() {
  var results = this.props.files.filter(function(file){
    return file.file.indexOf(this.state.query) > -1
  }, this)

  this.setState({
    results: results
  });
},

And slicing the results based on startand limitin the rendermethod:

和切片成果的基础上start,并limitrender方法:

render: function() {
  var files = this.state.results.slice(this.state.start, this.state.start + this.props.limit)
  return (
    <div>
      <Search onSearch={this.onSearch} onKeyDown={this.onKeyDown} />
      <List files={files} selected={this.state.selected - this.state.start} />
    </div>
  )
}

Fiddle containing a full working example: https://jsfiddle.net/koenpunt/hm1xnpqk/

包含完整工作示例的小提琴:https: //jsfiddle.net/koenpunt/hm1xnpqk/

回答by RationalDev likes GoFundMonica

Try filter before loading into the React component and only show a reasonable amount of items in the component and load more on demand. Nobody can view that many items at one time.

在加载到 React 组件之前尝试过滤器,只显示组件中合理数量的项目,并根据需要加载更多。没有人可以一次查看这么多项目。

I don't think you are, but don't use indexes as keys.

我不认为你是,但不要使用索引作为键

To find out the real reason why the development and production versions are different you could try profilingyour code.

要找出开发和生产版本不同的真正原因,您可以尝试profiling您的代码。

Load your page, start recording, perform a change, stop recording and then check out the timings. See here for instructions for performance profiling in Chrome.

加载您的页面,开始录制,执行更改,停止录制,然后查看时间。有关Chrome 中性能分析的说明,请参见此处

回答by Meemaw

For anyone struggling with this problem I have written a component react-big-listthat handles lists to up to 1 million of records.

对于任何在这个问题上苦苦挣扎的人,我编写了一个组件react-big-list来处理多达 100 万条记录的列表。

On top of that it comes with some fancy extra features like:

最重要的是,它具有一些奇特的额外功能,例如:

  • Sorting
  • Caching
  • Custom filtering
  • ...
  • 排序
  • 缓存
  • 自定义过滤
  • ...

We are using it in production in quite some apps and it works great.

我们在相当多的应用程序中在生产中使用它,并且效果很好。