Пример кода: https://github.com/d6u/example-redux-update-nested-props/blob/master/one-connect/index.js
Открыть демо-версию: http://d6u.github.io/example-redux-update-nested-props/one-connect.html
Как оптимизировать небольшие обновления для реквизитов вложенного компонента?
У меня выше компонентов, Repo и RepoList. Я хочу обновить тег первого репо (Строка 14). Поэтому я отправил действие UPDATE_TAG
. Прежде чем я выполнил shouldComponentUpdate
, отправка займет около 200 мс, что ожидается, так как мы тратим много времени на изменение <Repo/>
, которые не изменились.
После добавления shouldComponentUpdate
отправка занимает около 30 мс. После сборки сборки React.js обновления будут стоить около 17 мс. Это намного лучше, но просмотр временной шкалы в консоли Chrome dev по-прежнему показывает jank-фрейм (длиннее 16,6 мс).
Представьте себе, если у нас много таких обновлений, или <Repo/>
более сложный, чем текущий, мы не сможем поддерживать 60 кадров в секунду.
Мой вопрос заключается в том, что для таких небольших обновлений для реквизита вложенных компонентов существует более эффективный и канонический способ обновления содержимого? Могу ли я использовать Redux?
Я получил решение, заменив каждый tags
на наблюдаемый внутренний редуктор. Что-то вроде
// inside reducer when handling UPDATE_TAG action
// repos[0].tags of state is already replaced with a Rx.BehaviorSubject
get('repos[0].tags', state).onNext([{
id: 213,
text: 'Node.js'
}]);
Затем я подписываюсь на их значения внутри компонента Repo, используя https://github.com/jayphelps/react-observable-subscribe. Это отлично поработало. Каждая отправка только стоит 5 мс даже с разработкой React.js. Но я чувствую, что это анти-шаблон в Redux.
Обновление 1
Я следил за рекомендацией в ответе Дэна Абрамова и нормализовал мое состояние и обновленные компоненты подключения
Новая форма состояния:
{
repoIds: ['1', '2', '3', ...],
reposById: {
'1': {...},
'2': {...}
}
}
Я добавил console.time
вокруг ReactDOM.render
во время первоначальный рендеринг.
Однако производительность хуже, чем раньше (как первоначальная рендеринг, так и обновление). (Источник: https://github.com/d6u/example-redux-update-nested-props/blob/master/repo-connect/index.js, демо-версия: http://d6u.github.io/example-redux-update-nested-props/repo-connect.html)
// With dev build
INITIAL: 520.208ms
DISPATCH: 40.782ms
// With prod build
INITIAL: 138.872ms
DISPATCH: 23.054ms
Я думаю, что соединение на каждом <Repo/>
имеет много накладных расходов.
Обновление 2
Основываясь на обновленном ответе Дэна, мы должны вернуть аргументы connect
mapStateToProps
, вместо этого возвращая функцию. Вы можете проверить ответ Дэна. Я также обновил демо.
Ниже, производительность намного лучше на моем компьютере. И просто для удовольствия, я также добавил побочный эффект в подходе редуктора, о котором я говорил (источник, (серьезно не использовать его, только для эксперимента).
// in prod build (not average, very small sample)
// one connect at root
INITIAL: 83.789ms
DISPATCH: 17.332ms
// connect at every <Repo/>
INITIAL: 126.557ms
DISPATCH: 22.573ms
// connect at every <Repo/> with memorization
INITIAL: 125.115ms
DISPATCH: 9.784ms
// observables + side effect in reducers (don't use!)
INITIAL: 163.923ms
DISPATCH: 4.383ms
Обновление 3
Просто добавлен реактивно-виртуализированный пример на основе "connect at every with memorization"
INITIAL: 31.878ms
DISPATCH: 4.549ms