Производительность - не проблема. Пока не будет.

Это первая публикация из серии из трех частей, в которых объясняются некоторые уроки, полученные при использовании React в производственной среде.

вступление

Работая над MVP для Infleux, команда решила двигаться быстрее и оптимизировать позже. Мы знали, что приложение в конечном итоге столкнется с некоторыми проблемами нефункциональных требований, но если бизнес-модель даже не работает, какой смысл в ранней оптимизации и чрезмерной разработке?

Платформа

Infleux - это платформа для соединения брендов и влиятельных лиц!

Мы использовали следующие инструменты:

  1. create-react-app: Запустите приложение React.js с предварительно настроенными webpack и babel.
  2. redux: Библиотека управления состоянием, которую можно использовать с React.js
  3. redux-saga: Библиотека побочных эффектов (например, асинхронных действий) с redux.

Проблемы

После нескольких итераций бизнеса и приложения у нас наконец была стабильная версия, и начали проявляться некоторые проблемы:

  1. Проблемы с производительностью: платформа в целом казалась «вялой», прокрутка была медленной, простое переключаемое меню открывалось / закрывалось дольше, чем требовалось.
  2. Файловая структура проекта: мы начали со структуры папок в стиле Rails, то есть с отдельных папок для actions, constants, containers, reducers, components и sagas, но обнаружили некоторые проблемы с этим.
  3. Размер пакета: наш пакет SPA, файл, отправленный клиенту, становился все больше и больше с каждой добавленной функцией.

Я напишу сообщение по каждой теме - подробное описание всего в одном сообщении сделало бы его слишком длинным, а идея состоит в том, чтобы сделать его кратким.

Решение проблем с производительностью

Инструменты

Для анализа я использовал в основном Chrome DevTools и React Developer Tools. Это действительно мощные инструменты, которые очень помогают при отладке.



Одна действительно полезная функция этого инструмента заключается в том, что он позволяет вам выделять, какие компоненты обновляются. Чтобы включить его, откройте Chrome DevTools, перейдите на вкладку React и установите флажок «Выделить обновления».

Производные данные

Чтобы воспроизвести проблему, с которой мы столкнулись, я разветвил CodeSandbox (оригинал), который реализует пример списка Todo из redux docs, и внес в него некоторые изменения:

  1. Показать меню - это кнопка, которая переключает фильтры Todo.
  2. Изменена функция getVisibleTodos на todos.js для использования метода фильтрации.

Вот и CodeSandbox.

Каждый раз, когда нажимается кнопка для открытия / закрытия меню, список дел также обновляется, даже если было изменено несвязанное значение! Что ж, у нашего приложения был очень длинный список (множество узлов DOM), который постоянно перерисовывался при каждом взаимодействии, что замедляло работу. Так…

Почему это происходит?

Эта часть кода является виновником:

Что происходит, так это то, что каждый раз, когда вызывается функция mapStateToProps, функция getVisibleTodos возвращает новый массив, и это делает TodoList повторный рендеринг, потому что:

Чтобы изменить это поведение, вам нужно будет либо изменить mapStateToProps, либо shouldComponentUpdate() компонента.

Изменение shouldComponentUpdate() будет зависеть от оптимизируемых данных и компонента, и это может означать проблемы с масштабируемостью (должны ли мы оптимизировать каждый новый компонент React в соответствии с экраном? Как насчет повторного использования?), Поэтому мы отложили это решение.

Другой вариант, улучшить mapStateToProps, на самом деле является рекомендуемым подходом. Я изменил предыдущую песочницу, чтобы использовать reselect, и мы видим, что список больше не обновляется при нажатии кнопки меню! ("Ссылка")

Что делает reselect? Это мемоизированный селектор, означающий, что он кэширует результат с учетом входных данных и возвращает то же значение / ссылку, что означает, что строгое равенство (===) возвращает true.

Заявление об ограничении ответственности: это пример из reselect’s motivation.

Стрелочные функции

Да, встроенные стрелочные функции могут быть проблематичными. Стрелочная функция имеет ту же проблему, что и вычисление производных данных: новая функция передается при каждой визуализации. Это может привести к ненужному повторному рендерингу.

Из Официальной документации React:

Использование стрелочной функции при рендеринге создает новую функцию каждый раз при рендеринге компонента, что может повлиять на производительность (см. Ниже).

Подробнее по этой теме

Чистые компоненты

PureComponent выполняет поверхностное сравнение свойств и состояния и снижает вероятность пропуска необходимого обновления. (Из React Docs)

PureComponent реализует shouldComponentUpdate жизненный цикл.

shouldComponentUpdate() вызывается перед рендерингом при получении новых свойств или состояния. По умолчанию true.

то есть, когда вы используете Component, ваши компоненты повторно визуализируют каждое props или state изменение, независимо от изменения.

Виртуализация

Кроме того, другое возможное решение, которое можно было применить в нашем случае (чего мы не использовали по причинам, связанным с нашим дизайном), заключалось в использовании react-virtualized, то есть он отображает только то, что видно на экране.

Это действительно полезно, когда у вас есть большие списки изображений и вы не хотите, чтобы пользователь загружал их все до того, как они действительно появятся на экране.

Проблемы без реагирования

У нас также были некоторые проблемы, не связанные с React, которые влияли на производительность:

  1. использование border-radius на iPhone ДЕЙСТВИТЕЛЬНО замедляло прокрутку списков. Мы только что удалили его с мобильного, но то, что происходило, до сих пор меня интригует.
  2. Стиль наведения тахионов имеет transform: translateZ(0); для принудительного рендеринга графическим процессором, и это замедляло прокрутку для мобильных пользователей.

Как вы могли заметить, некоторые из наших проблем на самом деле являются оговорками в большей части официальной документации, но, как говорится:

Некоторые уроки лучше усвоить на собственном горьком опыте.

Привет сообществу

Одна из действительно крутых вещей в работе с OSS заключается в том, что у других людей, вероятно, были те же проблемы, с которыми вы сталкиваетесь, и вы никогда не одиноки, когда что-то отлаживаете, поэтому я хотел бы связать некоторые сообщения / статьи, которые помогли мне, когда отладка и изучение производительности React.js:





Подробнее откуда это взялось

Эта история публикуется в журнале Noteworthy, куда ежедневно приходят тысячи людей, чтобы узнать о людях и идеях, формирующих наши любимые продукты.

Следите за нашей публикацией, чтобы увидеть больше историй о продуктах и ​​дизайне, представленных командой Journal.