Приложения с высокой производительностью и стабильной реакцией

Обновлено: апрель 2020 г.

Прошло пять лет с тех пор, как я начал работать с React. Сейчас я использую React в своем 6-м производственном приложении. Он сильно повзрослел, он действительно стабилен и действительно забавен в использовании. Я начал использовать React + Flux, затем перешел на React + Redux, теперь я использую старый простой React с настраиваемой реализацией хранилища памяти.

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

Что касается моих взглядов, то я не хотел останавливаться на достигнутом, как Airbnb. Если вы когда-либо использовали веб-приложение Airbnb, вы заметите, насколько оно глючное и медленное. По тому, как приложение отображает, я легко могу заметить, что они пытались отобразить маршрут внутри шаблона, и это в конечном итоге обернулось катастрофой. Если бы это был я, я бы переделал все веб-приложение.

Мои нынешние пользователи - это действительно старая школа, старые телефоны, старые компьютеры и действительно устаревшие браузеры, поэтому мне нужно было максимизировать производительность рендеринга. После нескольких итераций я в конце концов придумал смешивать классы ES6 с шаблонами.

Он имеет готовый шаблон с 4 методами рендеринга. renderBody, renderHeader, renderFooter и render. Я расширяю шаблон по всему приложению и просто заменяю метод renderBody в представлениях. Затем я просто визуализирую все маршруты динамически в файле App.jsx. Когда мне нужно заменить верхний или нижний колонтитул, я просто заменяю метод renderHeader или renderFooter и возвращаю null.

Вы можете подумать, что это неэффективно, потому что он повторно отображает верхний и нижний колонтитулы при каждом изменении маршрута. Да, это правда, но он масштабируется в 100 раз лучше, чем реализация основного файла и добавление всех маршрутов внутри этого файла. Вы когда-нибудь пробовали провал рекламного менеджера в Facebook? Как вы думаете, это произошло?

Что насчет Redux

Redux, Redux, Redux. Примерно через год я пришел к выводу, что Redux только усложняет задачу. В наши дни я рекомендую реализовать Indexeddb и компонент высокого порядка, который обертывает каждое представление необходимыми данными. В долгосрочной перспективе это не только улучшит масштабирование, но и будет работать быстрее и эффективнее.

Поймите, что React - это библиотека

Первое, что нужно понять, это то, что React - это библиотека, а не фреймворк. На самом деле это означает, что нет единого способа делать что-то с React. Задача разработчика - установить стандарт для проекта. У каждого проекта разные требования, вам нужно найти то, что вам подходит. Если вам неловко, значит, вы, вероятно, делаете что-то не так. Если вы впервые делаете одностраничное приложение и вам нужно что-то, что даст вам больше структуры, попробуйте Vue.

Все дело в строке запроса

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

Что-то, что людям нравится в React, - это способность сохранять состояние при поверхностном рендеринге. Но я видел много разработчиков, пытающихся использовать состояние для сохранения вещей, определяющих область действия страницы. Проблема в том, что государство действительно не обеспечивает стабильности. Государство не «бессмертно». Отличный способ повысить стабильность вашего приложения - это переместить глобальные состояния в строку запроса. Другими словами, вам нужно определить объем страницы в строке запроса. Вы сохраняете расположение страницы и используете componentWillReceiveProps для отслеживания изменений в строке запроса. Таким образом, когда вы обновите страницу, все должно работать так, как должно.

Красота неизменности

Второе, что нужно знать о React, это то, что React повторно визуализирует все дерево Dom при каждом изменении свойств или состояния. Лучший способ справиться с этим - использовать PureComponents и следить за тем, чтобы ссылки менялись каждый раз при изменении объекта (попробуйте поискать в Google неизменяемость). При изменении состояния или свойств никогда не используйте один и тот же объект или массив, создайте новый с помощью оператора распространения (… объект). Таким образом, когда компонент проверяет, изменился ли объект, вам не нужно проводить тщательную проверку.

Ограничьте количество отправляемых вами реквизитов

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

Избегайте встроенных стилей по любой причине

Использование встроенных стилей приводит к огромному снижению производительности. У createElement уходит много времени на прохождение каждого определяющего стиля и его рендеринга в Dom.

Избегайте действий до установки компонента.

Уловка, связанная с высокой производительностью, не в том, чтобы сделать компоненты на самом деле быстрее. Суть в том, чтобы заставить пользователя думать, что приложение работает очень быстро. Первое, что вам нужно сделать, это понять, что должно происходить асинхронно и синхронно. Лучший способ отрисовать страницу - сначала отрендерить все, а после отрисовки страницы выполнить тяжелую работу. (не делайте ничего синхронного в componentWillMount). Все, что отнимает много времени и требует синхронного времени, делается в componentDidMount.

Используйте только контролируемые компоненты, когда это необходимо

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

Сохранение состояния компонента рядом с простыми методами рендеринга

Хотя я рекомендую иметь всю бизнес-логику внутри контейнера. Постарайтесь сохранить состояние контролируемых компонентов с помощью простых методов рендеринга. Это означает, что вам следует избегать объявления состояния в родительском компоненте, потому что каждый раз, когда вы меняете состояние, он должен будет проходить через каждый компонент, повторно визуализируя все дерево.

Все дело в разделении приложения

Почему развязка ??? Легко: чем больше модулируется ваше приложение, тем быстрее оно будет работать. Есть несколько вещей, которые заставят ваше приложение работать в 100 раз быстрее при разделении вашего приложения. Во-первых, вы можете выполнять разделение кода с помощью React Router, что позволяет загружать код быстрее. Во-вторых, когда вы отделяете свое приложение React, вы также разделяете деревья рендеринга. Дело в этом примерно так. Допустим, у вас есть три раздела в вашем приложении, во-первых, незащищенный раздел, который в основном содержит вашу страницу входа. Второй раздел содержит вашу панель инструментов, в которой есть все функции вашего приложения. Последний раздел - это ваш профиль и раздел настроек. Теперь предположим, что вы используете свою панель управления и обновляете свои данные каждые 30 секунд, если ваше дерево рендеринга знает о странице входа. React все равно придется пройти через эту часть дерева. Когда вы разделяете свой код на уровне маршрута / контейнера, эта часть приложения не будет в дереве рендеринга.

Избегайте React.createElement

Недавно я проводил некоторое тестирование по оптимизации React и нашел изящный трюк для улучшения компонентов без сохранения состояния. Когда вы добавляете компонент в метод рендеринга с помощью JSX (‹Component someProps = {someProps} /›), он вызывает функцию createElement и фактически снижает производительность при повторном рендеринге. Если вы создаете компонент как функцию, подобную этой:

{ Component({someProps}) }

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

Воспользуйтесь услугами сервисных работников

Сервисные работники удивительны, когда они доступны. Они позволяют вам без труда регистрировать ваши скрипты, что оптимизирует время загрузки ваших скриптов. Эта функция отлично подходит при работе с очень медленными сетями (также известные как смартфоны).

Подробнее об Оптимизации производительности React здесь.

Если вам понравилась эта статья, нажмите на зеленое сердечко внизу, чтобы другие могли ею насладиться. Также, пожалуйста, задавайте вопросы или оставляйте заметки с любыми полезными практиками.

Подписывайтесь на меня в твиттере @nesbtesh