Я в процесі впровадження списку, який можна фільтрувати, за допомогою React. Структура списку така, як показано на малюнку нижче.
ПРОМІСЛЯ
Ось опис того, як це має працювати:
- Стан знаходиться в компоненті найвищого рівня -
Searchкомпоненті. - Стан описується наступним чином:
{
видимий: логічний,
файли: масив,
відфільтровано: масив,
запит: рядок,
currentlySelectedIndex: ціле число
}
files- потенційно дуже великий масив, що містить шляхи до файлів (10000 записів - це ймовірне число).filtered- це відфільтрований масив після того, як користувач введе принаймні 2 символи. Я знаю, що це похідні дані, і як такий аргумент можна навести аргумент щодо їх зберігання у штаті, але це потрібно дляcurrentlySelectedIndexщо є індексом поточно вибраного елемента із відфільтрованого списку.Користувач вводить у
Inputкомпонент більше 2 літер , масив фільтрується і для кожного запису у відфільтрованому масиві відображаєтьсяResultкомпонентКожен
Resultкомпонент відображає повний шлях, який частково відповідає запиту, а частина шляху часткового збігу виділяється. Наприклад, DOM компонента Result, якби користувач набрав 'le', був би приблизно таким:<li>this/is/a/fi<strong>le</strong>/path</li>- Якщо користувач натискає клавіші вгору або вниз, коли
Inputкомпонент фокусується,currentlySelectedIndexзміни базуються наfilteredмасиві. Це призводить до того, щоResultкомпонент, що відповідає індексу, буде позначений як вибраний, що спричинить повторне відображення
ПРОБЛЕМА
Спочатку я перевірив це з досить невеликим масивом files, використовуючи розробницьку версію React, і все працювало нормально.
Проблема з’явилася, коли мені довелося мати справу з filesмасивом розміром до 10000 записів. Введення 2-х літер у введенні створить великий список, і коли я натискаю клавіші вгору і вниз для навігації, це буде дуже відсталим.
Спочатку у мене не було визначеного компонента для 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));
Як ви можете зрозуміти, щоразу, коли currentlySelectedIndexзмінене, це призведе до повторного відтворення, і список буде створюватись кожного разу. Я думав, що оскільки я встановив keyзначення для кожного liелемента, React буде уникати повторного відтворення кожного іншого liелемента, який не classNameзазнав змін, але, мабуть, це було не так.
Я в кінцевому підсумку визначив клас для 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>
);
}
});
І список тепер створюється як такий:
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));
}
Це покращило продуктивність , але вона все ще недостатньо хороша. Справа в тому, що коли я тестував на виробничій версії React, все працювало згладжено, без затримок.
НИЖНЯ ЛІНІЯ
Чи є така помітна розбіжність між розробницькою та виробничою версіями React нормальною?
Я розумію / роблю щось не так, коли думаю про те, як React керує списком?
ОНОВЛЕННЯ 14-11-2016
Я знайшов цю презентацію Майкла Джексона, де він вирішує проблему, дуже подібну до цієї: https://youtu.be/7S8v8jfLb1Q?t=26m2s
Рішення дуже схожий на той , запропонований AskarovBeknar в відповідь нижче
ОНОВЛЕННЯ 14-4-2018
Оскільки це, мабуть, популярне запитання, і з того часу, як було поставлено вихідне запитання, справи просунулись, хоча я закликаю вас переглянути відео, на яке посилається вище, щоб зрозуміти віртуальний макет, я також рекомендую вам використовувати React Virtualized бібліотеки, якщо ви не хочете заново винаходити колесо.



