Вот некоторые антипаттерны, наиболее часто встречающиеся в приложениях React, и способы их устранения. Эти антипаттерны превратят вашу кодовую базу в кошмар для работы, если вы не научитесь распознавать и предотвращать их на ранних стадиях.
Помещаем все в Redux
Redux - это потрясающе. Он оптимизирует производительность за кулисами и позволяет нам легко получить доступ к глобальному состоянию приложения.
Проблема в том, что как только новые разработчики осваивают Redux, они начинают использовать его как волшебную палочку для решения всех своих проблем.
У такого подхода есть несколько недостатков:
Ваш код теряет смысл. Если все в Redux, то неясно, должен ли ваш код иметь локальную или глобальную область видимости. Вносить изменения сложнее, потому что вы менее уверены в том, какие части приложения будут затронуты.
Производительность снижается, когда вы используете Redux для частых событий, например, для отслеживания ввода формы. Поскольку Redux влияет на глобальное состояние приложения, он гарантированно вызовет больше повторных рендеров.
Экономное правило: Используйте Redux только для действительно глобальных данных, таких как сессия пользователя или тема приложения. Для всего остального я предпочитаю создавать контексты для конкретных частей приложения.
Хранение всего как состояния
Еще одна проблема, с которой сталкиваются начинающие разработчики, - недостаточное использование концепции производного состояния.
Многие переменные можно вычислять на лету. Например, у вас есть массив элементов флажка. Вам не нужно хранить checkedCount в состоянии. Вы можете вычислить checkedCount, пройдя через массив элементов и отфильтровав отмеченные при каждом рендере.
Экономное правило: Прежде чем хранить переменную в состоянии, спросите себя: "Могу ли я как-то вывести эту переменную на основе других данных, которые я уже храню?".
Передача реквизитов с помощью оператора spread повсеместно
Я часто встречал этот трюк в приложениях React.
Вы передаете реквизиты дочернему компоненту с помощью {...props}. Это выглядит аккуратно, и вы можете подумать, что делаете свой код более лаконичным. Но правда в том, что со временем ваш код станет менее предсказуемым и более сложным для понимания.
Когда вы начинаете передавать реквизиты с помощью оператора spread везде, не сразу становится понятно, какие реквизиты действительно нужны вашим дочерним компонентам. Рефакторинг становится практически невозможным. Даже небольшие усилия по рефакторингу откроют целый ворох проблем. Кроме того, гораздо сложнее отслеживать ошибки в дереве компонентов.
Эмпирическое правило: Как правило, избегайте передачи реквизитов с помощью оператора spread. Единственный случай, когда это оправдано, - написание компонента-контейнера или HOC, который отображает и улучшает свои дочерние компоненты.
Объявление компонентов внутри компонентов
Объявление компонента внутри другого компонента выглядит следующим образом:
Написание компонентов внутри их родителей - плохая идея по двум причинам:
Ваш код становится тесно связанным. Ваш внутренний компонент становится зависимым от области закрытия его родителя.
Производительность снижается. Родительский компонент будет заново создавать функцию объявления дочернего компонента при каждом рендере.
Главное правило: Избегайте объявления компонентов внутри их родителей.
Передача слишком большого количества информации компонентам
Полезно быть скупым в том, как много вы позволяете знать своим компонентам. При принятии решения о том, сколько данных передавать, старайтесь помнить о разделении между интеллектуальными и презентационными компонентами.
Презентационные компоненты - это компоненты, которые выводят только HTML. Они не хранят состояние и не обрабатывают никакой поведенческой логики.
Умные компоненты обычно обрабатывают состояние и предоставляют данные и поведение презентационным компонентам, делая API-запросы, мутируя redux и т.д.
В презентационные компоненты следует передавать только те данные, которые необходимы для рендеринга. Презентационные компоненты не должны решать, выводить ли их содержимое. Этой логикой должны заниматься интеллектуальные компоненты.
При осмотре родительского компонента неясно, что наш дочерний компонент имеет логику условного рендеринга. Мы можем прояснить этот код, повторно разместив условную логику и позволив родительскому компоненту решать, рендерить ли дочерний компонент.
Когда это возможно, передавайте презентационным компонентам только примитивы. Это упрощает последующую оптимизацию их работы.
Это позволяет сократить количество повторных рендеров с помощью React.memo. Причина в том, что React сравнивает реквизиты объектов на основе ссылки, в то время как примитивы сравниваются на основе значения.
Подводя итог, вот проблемы, связанные с передачей слишком большого количества информации компонентам:
Трудно отличить интеллектуальные компоненты от презентационных. Основная логика вашего приложения должна обрабатываться интеллектуальными компонентами, в то время как презентационные компоненты только выводят HTML.
Производительность ухудшается. Если вы передаете компоненту слишком много реквизитов, он будет перерисовываться каждый раз, когда эти реквизиты меняются, что приводит к избыточным перерисовкам.
Чрезмерная оптимизация производительности
Иногда разработчики начинают оптимизировать свой код до того, как возникнет реальная проблема. Это плохая практика по двум простым причинам:
Сложный и чрезмерно продуманный код. Попытка решить проблему до того, как она возникнет, - самый верный способ переусложнить код.
Зря потраченное время. Вместо этого вы могли бы создавать новые функции и решать важные проблемы.
По моему опыту, разумное разделение интеллектуальных и презентационных компонентов решает ~90% проблем с производительностью в приложениях React.
Огромные деревья компонентов
Последнее, но не менее важное - это большие деревья компонентов.
Обычно эта проблема возникает, когда вы не уделяете время правильному разделению логических и презентационных частей кода.
Неприятно, правда? Очень трудно расшифровать, что здесь происходит. У нас есть несколько областей для улучшения:
Переделайте длинные условные операторы в отдельные переменные.
Разделить части дерева на более мелкие презентационные компоненты.
Переместить обработчики функций стрелок из дерева компонентов.
Это дерево компонентов выглядит намного лучше.
Эмпирическое правило: Держите деревья компонентов в чистоте, чтобы было легче понять, что и когда должен отображать компонент.
Заключение
В этом посте мы рассмотрели антипаттерны React и то, как их можно избежать. Избегая этих антишаблонов с самого начала, вам не придется тратить много времени на рефакторинг кода в будущем.