Hiệu suất danh sách lớn với React


86

Tôi đang trong quá trình triển khai danh sách có thể lọc với React. Cấu trúc của danh sách như trong hình dưới đây.

nhập mô tả hình ảnh ở đây

LỜI NÓI ĐẦU

Dưới đây là mô tả về cách nó hoạt động:

  • Trạng thái nằm trong thành phần cấp cao nhất, Searchthành phần.
  • Trạng thái được mô tả như sau:
{
    hiển thị: boolean,
    tệp: mảng,
    lọc: mảng,
    chuỗi truy vấn,
    hiệnSelectedIndex: số nguyên
}
  • files là một mảng có khả năng rất lớn, chứa các đường dẫn tệp (10000 mục nhập là một con số hợp lý).
  • filteredlà mảng được lọc sau khi người dùng nhập ít nhất 2 ký tự. Tôi biết đó là dữ liệu phái sinh và như vậy có thể lập luận về việc lưu trữ nó ở trạng thái nhưng nó cần thiết để
  • currentlySelectedIndex là chỉ mục của phần tử hiện được chọn từ danh sách đã lọc.

  • Người dùng nhập nhiều hơn 2 chữ cái vào Inputthành phần, mảng được lọc và đối với mỗi mục nhập trong mảng được lọc, một Resultthành phần được hiển thị

  • Mỗi Resultthành phần đang hiển thị đường dẫn đầy đủ khớp một phần với truy vấn và phần khớp một phần của đường dẫn được đánh dấu. Ví dụ: DOM của một thành phần Kết quả, nếu người dùng đã nhập 'le' sẽ giống như sau:

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

  • Nếu người dùng nhấn các phím lên hoặc xuống trong khi Inputthành phần được lấy nét, các currentlySelectedIndexthay đổi dựa trên filteredmảng. Điều này khiến Resultthành phần phù hợp với chỉ mục được đánh dấu là đã chọn gây ra kết xuất lại

VẤN ĐỀ

Ban đầu, tôi đã thử nghiệm điều này với một mảng đủ nhỏ files, sử dụng phiên bản phát triển của React và tất cả đều hoạt động tốt.

Sự cố xuất hiện khi tôi phải xử lý một filesmảng lớn tới 10000 mục nhập. Việc gõ 2 chữ cái vào Input sẽ tạo ra một danh sách lớn và khi tôi nhấn phím lên và xuống để điều hướng nó sẽ rất chậm.

Lúc đầu, tôi không có một thành phần xác định cho các Resultphần tử và tôi chỉ đang lập danh sách một cách nhanh chóng, trên mỗi lần hiển thị của Searchthành phần, chẳng hạn như:

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));

Như bạn có thể nói, mỗi lần currentlySelectedIndexthay đổi, nó sẽ tạo ra một kết xuất lại và danh sách sẽ được tạo lại mỗi lần. Tôi nghĩ rằng vì tôi đã đặt một keygiá trị trên mỗi liphần tử nên React sẽ tránh hiển thị mọi liphần tử khác không có sự classNamethay đổi của nó , nhưng rõ ràng là không phải như vậy.

Tôi đã kết thúc việc xác định một lớp cho các Resultphần tử, nơi nó kiểm tra rõ ràng xem mỗi Resultphần tử có nên hiển thị lại hay không dựa trên việc liệu nó đã được chọn trước đó hay chưa và dựa trên đầu vào của người dùng hiện tại:

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>
        );
    }
});

Và danh sách bây giờ được tạo như sau:

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));
}

Điều này làm cho hiệu suất tốt hơn một chút , nhưng nó vẫn chưa đủ tốt. Điều đó là khi tôi thử nghiệm trên phiên bản sản xuất của React, mọi thứ hoạt động rất mượt mà, không có độ trễ nào cả.

ĐÁP ÁN

Sự khác biệt đáng chú ý như vậy giữa các phiên bản phát triển và sản xuất của React có bình thường không?

Tôi có hiểu / đang làm gì sai khi nghĩ về cách React quản lý danh sách không?

CẬP NHẬT 14-11-2016

Tôi đã tìm thấy bài thuyết trình này của Michael Jackson, nơi anh ấy giải quyết một vấn đề rất giống với bài thuyết trình này: https://youtu.be/7S8v8jfLb1Q?t=26m2s

Giải pháp rất giống với giải pháp được đề xuất bởi câu trả lời của AskarovBeknar , bên dưới

CẬP NHẬT 14-4-2018

Vì đây rõ ràng là một câu hỏi phổ biến và mọi thứ đã tiến triển kể từ khi câu hỏi ban đầu được hỏi, trong khi tôi khuyến khích bạn xem video được liên kết ở trên, để nắm bắt được bố cục ảo, tôi cũng khuyến khích bạn sử dụng React Virtualized thư viện nếu bạn không muốn phát minh lại bánh xe.


Bạn hiểu phiên bản phát triển / sản xuất của react là gì?
Dibesjr


Ah tôi hiểu rồi, cảm ơn. Vì vậy, để trả lời một trong những câu hỏi của bạn, nó cho biết có sự khác biệt trong việc tối ưu hóa giữa các phiên bản. Một điều cần chú ý trong các danh sách lớn là tạo các hàm trong kết xuất của bạn. Nó sẽ có hiệu suất cao khi bạn lọt vào danh sách khổng lồ. Tôi sẽ thử và xem mất bao lâu để tạo danh sách đó bằng cách sử dụng các công cụ hiệu quả của họ facebook.github.io/react/docs/perf.html
Dibesjr

2
Tôi nghĩ bạn nên xem xét lại việc sử dụng Redux vì nó chính xác là thứ bạn cần ở đây (hoặc bất kỳ loại triển khai thông lượng nào). Bạn dứt khoát nên hãy nhìn vào bài trình bày này: Big Danh sách High Performance Phản ứng & Redux
Pierre Criulanscy

2
Tôi nghi ngờ rằng người dùng có bất kỳ lợi ích nào khi cuộn qua 10000 kết quả. Vì vậy, điều gì sẽ xảy ra nếu bạn chỉ hiển thị 100 kết quả hàng đầu hoặc lâu hơn và cập nhật những kết quả này dựa trên truy vấn.
Koen.

Câu trả lời:


18

Như với nhiều câu trả lời khác cho câu hỏi này, vấn đề chính nằm ở thực tế là việc hiển thị quá nhiều phần tử trong DOM trong khi thực hiện lọc và xử lý các sự kiện chính sẽ diễn ra chậm.

Bạn vốn dĩ không làm gì sai liên quan đến React gây ra sự cố nhưng giống như nhiều vấn đề liên quan đến hiệu suất, giao diện người dùng cũng có thể chiếm một phần lớn nguyên nhân.

Nếu giao diện người dùng của bạn không được thiết kế với tính hiệu quả, ngay cả các công cụ như React được thiết kế để hoạt động hiệu quả cũng sẽ bị ảnh hưởng.

Lọc tập hợp kết quả là một bước khởi đầu tuyệt vời như @Koen đã đề cập

Tôi đã thử với ý tưởng này một chút và tạo một ứng dụng ví dụ minh họa cách tôi có thể bắt đầu giải quyết loại vấn đề này.

Đây không phải là production readymã nhưng nó minh họa khái niệm đầy đủ và có thể được sửa đổi để mạnh mẽ hơn, vui lòng xem mã - tôi hy vọng ít nhất nó cũng cung cấp cho bạn một số ý tưởng ...;)

phản ứng-lớn-danh sách-ví dụ

nhập mô tả hình ảnh ở đây


1
Tôi thực sự cảm thấy tồi tệ khi chỉ phải chọn một câu trả lời, tất cả họ dường như đều đã nỗ lực hết mình, nhưng tôi hiện đang đi nghỉ mà không có PC và không thể thực sự kiểm tra chúng với sự chú ý mà họ xứng đáng được. Tôi chọn cái này vì nó đủ ngắn gọn và đúng trọng tâm, để hiểu ngay cả khi đọc từ điện thoại. Tôi biết lý do khập khiễng.
Dimitris Karagiannis

Ý bạn là gì khi chỉnh sửa tệp máy chủ lưu trữ 127.0.0.1 * http://localhost:3001?
stackjlei 29/09/17

@stackjlei Tôi nghĩ ý của anh ấy là ánh xạ 127.0.0.1 tới localhost: 3001 trong / etc / hosts
Maverick

16

Kinh nghiệm của tôi với một vấn đề tương tự là phản ứng thực sự bị ảnh hưởng nếu có hơn 100-200 hoặc hơn các thành phần trong DOM cùng một lúc. Ngay cả khi bạn cực kỳ cẩn thận (bằng cách thiết lập tất cả các khóa của bạn và / hoặc triển khai một shouldComponentUpdatephương pháp) để chỉ thay đổi một hoặc hai thành phần khi kết xuất lại, bạn vẫn sẽ ở trong một thế giới bị tổn thương.

Phần chậm của phản ứng vào lúc này là khi nó so sánh sự khác biệt giữa DOM ảo và DOM thực. Nếu bạn có hàng nghìn thành phần nhưng chỉ cập nhật một vài thành phần, điều đó không quan trọng, phản ứng vẫn có một hoạt động khác biệt lớn cần thực hiện giữa các DOM.

Khi tôi viết các trang bây giờ tôi cố gắng thiết kế chúng để giảm thiểu số lượng thành phần, một cách để làm điều này khi hiển thị danh sách lớn các thành phần là ... tốt ... không hiển thị danh sách lớn các thành phần.

Ý tôi là: chỉ hiển thị các thành phần bạn hiện có thể nhìn thấy, hiển thị nhiều hơn khi bạn cuộn xuống, bạn là người dùng không có khả năng cuộn xuống hàng nghìn thành phần theo bất kỳ cách nào .... Tôi hy vọng.

Một thư viện tuyệt vời để làm điều này là:

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

Với một hướng dẫn tuyệt vời ở đây:

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

Tôi e rằng nó không xóa các thành phần nằm ngoài đầu trang, vì vậy nếu bạn cuộn đủ lâu, các vấn đề về hiệu suất sẽ bắt đầu xuất hiện trở lại.

Tôi biết việc cung cấp một liên kết làm câu trả lời là không tốt, nhưng các ví dụ mà họ cung cấp sẽ giải thích cách sử dụng thư viện này tốt hơn nhiều so với những gì tôi có thể làm ở đây. Hy vọng rằng tôi đã giải thích tại sao danh sách lớn là xấu, nhưng cũng là một công việc xung quanh.


2
Cập nhật: gói có trong câu trả lời này không được duy trì. Một ngã ba được thiết lập trên npmjs.com/package/react-infinite-scroller
Ali Al Amin

11

Trước hết, sự khác biệt giữa phiên bản phát triển và sản xuất của React là rất lớn bởi vì trong quá trình sản xuất, có nhiều bước kiểm tra thông minh bị bỏ qua (chẳng hạn như xác minh loại prop).

Sau đó, tôi nghĩ bạn nên xem xét lại việc sử dụng Redux vì nó sẽ cực kỳ hữu ích ở đây cho những gì bạn cần (hoặc bất kỳ loại triển khai thông lượng nào). Chắc chắn bạn nên xem qua phần trình bày này: Big List High Performance React & Redux .

Nhưng trước khi đi sâu vào redux, bạn cần phải thực hiện một số điều chỉnh đối với mã React của mình bằng cách chia các thành phần của bạn thành các thành phần nhỏ hơn vì shouldComponentUpdatesẽ bỏ qua hoàn toàn việc hiển thị các phần tử con, vì vậy đó là một lợi ích lớn .

Khi bạn có nhiều thành phần chi tiết hơn, bạn có thể xử lý trạng thái với redux và react-redux để tổ chức luồng dữ liệu tốt hơn.

Gần đây tôi đang gặp phải sự cố tương tự khi tôi cần hiển thị một nghìn hàng và có thể sửa đổi từng hàng bằng cách chỉnh sửa nội dung của nó. Ứng dụng nhỏ này hiển thị danh sách các buổi hòa nhạc có các buổi hòa nhạc trùng lặp tiềm năng và tôi cần chọn từng bản sao tiềm năng nếu tôi muốn đánh dấu bản sao tiềm năng là buổi hòa nhạc gốc (không phải bản sao) bằng cách chọn hộp kiểm và nếu cần, hãy chỉnh sửa tên của buổi hòa nhạc. Nếu tôi không làm gì cho một mục trùng lặp tiềm năng cụ thể, nó sẽ được coi là trùng lặp và sẽ bị xóa.

Đây là những gì nó trông giống như:

nhập mô tả hình ảnh ở đây

Về cơ bản có 4 thành phần chính (chỉ có một hàng ở đây nhưng đó là vì lợi ích của ví dụ):

nhập mô tả hình ảnh ở đây

Đây là toàn bộ mã (CodePen hoạt động: Huge List với React & Redux ) sử dụng redux , react -redux , immutable , chọn lại và biên soạn lại :

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')
);

Bài học kinh nghiệm khi sử dụng ứng dụng nhỏ này khi làm việc với tập dữ liệu lớn

  • Các thành phần React hoạt động tốt nhất khi chúng được giữ nhỏ
  • Việc chọn lại trở nên rất hữu ích để tránh tính toán lại và giữ cho cùng một đối tượng tham chiếu (khi sử dụng immutable.js) với các đối số giống nhau.
  • Tạo connectthành phần ed cho thành phần gần nhất với dữ liệu mà họ cần để tránh việc thành phần chỉ chuyển xuống các đạo cụ mà chúng không sử dụng
  • Sử dụng chức năng vải để tạo mapDispatchToProps khi bạn chỉ cần hỗ trợ ban đầu được đưa vào ownPropslà cần thiết để tránh kết xuất vô ích
  • Phản ứng & redux dứt khoát cùng nhau!

2
Tôi không nghĩ rằng việc thêm phụ thuộc vào redux là cần thiết để giải quyết vấn đề của OP, các hành động điều phối hơn nữa để lọc tập kết quả của anh ấy sẽ chỉ làm phức tạp thêm vấn đề, việc gửi đi không rẻ như bạn nghĩ, xử lý tình huống cụ thể này với thành phần cục bộ nhà nước là phương pháp hiệu quả nhất
deowk

4
  1. React trong phiên bản phát triển kiểm tra các proptype của mỗi thành phần để dễ dàng quá trình phát triển, trong khi trong sản xuất, nó được bỏ qua.

  2. Lọc danh sách các chuỗi là hoạt động rất tốn kém cho mỗi lần gõ phím. nó có thể gây ra các vấn đề về hiệu suất vì bản chất đơn luồng của JavaScript. Giải pháp có thể được sử dụng debounce phương pháp để thực hiện chậm trễ của chức năng lọc của bạn cho đến khi sự chậm trễ là hết hạn.

  3. Một vấn đề khác có thể là bản thân danh sách khổng lồ. Bạn có thể tạo bố cục ảo và sử dụng lại các mục đã tạo chỉ thay thế dữ liệu. Về cơ bản, bạn tạo thành phần vùng chứa có thể cuộn với chiều cao cố định, bên trong đó bạn sẽ đặt vùng chứa danh sách. Chiều cao của vùng chứa danh sách nên được đặt theo cách thủ công (itemHeight * numberOfItems) tùy thuộc vào độ dài của danh sách hiển thị, để thanh cuộn hoạt động. Sau đó, tạo một vài thành phần mục để chúng lấp đầy chiều cao của vùng chứa có thể cuộn và có thể thêm một hoặc hai hiệu ứng danh sách liên tục bắt chước. đặt chúng ở vị trí tuyệt đối và khi cuộn chỉ cần di chuyển vị trí của chúng để nó sẽ bắt chước danh sách liên tục (tôi nghĩ bạn sẽ tìm ra cách triển khai nó :)

  4. Một điều nữa là việc ghi vào DOM cũng là một thao tác tốn kém, đặc biệt nếu bạn làm sai. Bạn có thể sử dụng canvas để hiển thị danh sách và tạo trải nghiệm mượt mà khi cuộn. Kiểm tra các thành phần canvas phản ứng. Tôi nghe nói rằng họ đã thực hiện một số công việc về Danh sách.


Bất kỳ thông tin về React in development? và tại sao kiểm tra các protoytpes của mỗi thành phần?
Liuuil

4

Hãy xem React Virtualized Select, nó được thiết kế để giải quyết vấn đề này và hoạt động ấn tượng theo kinh nghiệm của tôi. Từ mô tả:

HOC sử dụng phản ứng ảo hóa và chọn phản ứng để hiển thị danh sách lớn các tùy chọn trong trình đơn thả xuống

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


4

Giống như tôi đã đề cập trong nhận xét của mình , tôi nghi ngờ rằng người dùng cần tất cả 10000 kết quả đó trong trình duyệt cùng một lúc.

Điều gì sẽ xảy ra nếu bạn lướt qua các kết quả và luôn chỉ hiển thị danh sách 10 kết quả.

Tôi đã tạo một ví dụ bằng kỹ thuật này mà không sử dụng bất kỳ thư viện nào khác như Redux. Hiện chỉ với điều hướng bàn phím, nhưng cũng có thể dễ dàng mở rộng để hoạt động trên thao tác cuộn.

Ví dụ tồn tại 3 thành phần, ứng dụng vùng chứa, thành phần tìm kiếm và thành phần danh sách. Hầu như tất cả logic đã được chuyển đến thành phần vùng chứa.

Các ý chính nằm trong kiểm soát thường xuyên startselectedkết quả, và chuyển những người trên tương tác bàn phím.

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})
  }
},

Trong khi chỉ cần chuyển tất cả các tệp qua bộ lọc:

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

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

Và cắt các kết quả dựa trên startlimittrong renderphương pháp:

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 chứa một ví dụ hoạt động đầy đủ: https://jsfiddle.net/koenpunt/hm1xnpqk/


3

Hãy thử bộ lọc trước khi tải vào thành phần React và chỉ hiển thị một lượng hợp lý các mục trong thành phần và tải nhiều hơn theo yêu cầu. Không ai có thể xem nhiều mục cùng một lúc.

Tôi không nghĩ là bạn, nhưng đừng sử dụng các chỉ mục làm khóa .

Để tìm ra lý do thực sự khiến phiên bản phát triển và sản xuất khác nhau, bạn có thể thử profilingmã của mình.

Tải trang của bạn, bắt đầu ghi, thực hiện thay đổi, dừng ghi và sau đó kiểm tra thời gian. Xem tại đây để biết hướng dẫn về cấu hình hiệu suất trong Chrome .


2

Đối với bất kỳ ai đang gặp khó khăn với vấn đề này, tôi đã viết một thành phần react-big-listxử lý danh sách lên đến 1 triệu bản ghi.

Trên hết, nó đi kèm với một số tính năng bổ sung thú vị như:

  • Sắp xếp
  • Bộ nhớ đệm
  • Lọc tùy chỉnh
  • ...

Chúng tôi đang sử dụng nó trong sản xuất trong một số ứng dụng và nó hoạt động rất tốt.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.