- PVSM.RU - https://www.pvsm.ru -
Этот пост является продолжением поста про оптимизацию производительности списка в React приложении [1].
Внимание. В данном посте примеры подготовлены специально для Redux приложений. Но сам подход возможно применить и с другими библиотеками. Так же нижеприведенный совет работает в react-redux версии 5. Я не смог достичь желаемого результата в версии 4. Глубоко разбираться в причинах я не стал.
И так, стандартный способ хранить некоторое множество элементов в приложении — это хранить их в массиве:
const state = {
targets: [{id: 'target1', radius: 10}, {id: 'target2', radius: 2}]
};
Далее, скорее всего, где-то у вас в приложении будет компонент, который отображает этот список:
const TargetsList = connect(state => ({targets: state.targets}))(
({ targets }) =>
<ul>
{ targets.map((target) => <TargetView key={target.id} target={target} />) }
</ul>
);
Если вдруг вам нужно обновить один элемент, то придётся обновить весь массив (иммутабельненько же нужно):
function appReducer(state, action) {
if (action.type === 'UPDATE') {
return {
target: state.target.map((target) => {
if (target.id === action.id) {
return {
...target,
radius: action.radius
};
} else {
return target;
}
})
}
}
// some other code
}
Так же обновление элемента приведёт к обновлению всей вьюшки «TargetsList» (будет вызван его render).
Я сделал небольшое демо [2] с тестовым кодом для замера производительности.
На моей машине, обновление одного элемента в списке длиною 1000 занимает примерно 21мс. В предыдущем посте [1] я описал способ повышения прозводительности с помощью дополнительных подписок на изменения состояния в дочернем компоненте, а так же добавления некоторой логики в «shouldComponentUpdate» для компонента, который отображает список.
Но практически такой-же результат можно достичь небольшим изменением формы данных.
Если вы используете github.com/reactjs/react-redux [3], то вы можете увеличить прозводительность, изменив форму состояния на:
const state = {
targetsOrder: ['id-1', 'id-2'],
targets: {
'id-1': { id: 'id-1', radius: 10 },
'id-2': { id: 'id-2', radius: 20 },
}
};
Далее нужно немного изменить компонент «TargetsList»:
const TargetsList = connect(state => ({targetsOrder: state.targetsOrder}))(
({ targetsOrder }) =>
<ul>
{ targetsOrder.map((id) => <TargetView key={target.id} targetId={id} />) }
</ul>
);
Обратите внимание, что, в данном случае, я передаю в дочерний компонент ID элемента, а не весь элемент. Тогда «TargetView» не может быть «тупым компонентом» и должен подписаться на изменения в состоянии:
const TargetView = connect(
(state, ownProps) => ({target: state.targets[ownProps.targetId]})
)(({ target }) => {
// your render logic
return <Circle radius={target.radius} />;
});
Так как «TargetView» подписан на изменения в состоянии, он обновит сам себя, когда его данные обновятся. Важно то, что «TargetList» НЕ БУДЕТ обновлён при изменении элемента в списке потому, что «targetsOrder» остаётся тем же. В некоторых случаях такая техника может значительно повысить производительность.
→ Обновлённое демо с замерами [4]
Теперь обновление одного элемента занимает 2.2мс на моей машине. Это почти в 10 раз быстрее, чем в предыдущем примере.
Автор: lavrton
Источник [5]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/224338
Ссылки в тексте:
[1] поста про оптимизацию производительности списка в React приложении: https://habrahabr.ru/post/304340/
[2] небольшое демо: http://codepen.io/lavrton/pen/xRgYbL
[3] github.com/reactjs/react-redux: https://github.com/reactjs/react-redux
[4] Обновлённое демо с замерами: http://codepen.io/lavrton/pen/ZBLrWp
[5] Источник: https://habrahabr.ru/post/318268/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best
Нажмите здесь для печати.