Как стать автором
Обновить

React. Лёгкий способ бросить курить

Время на прочтение3 мин
Количество просмотров20K

Писать кнопочки и формочки на React - дело не хитрое. Но почти всегда фронтовые проекты превращаются в нечто трудночитаемое и едва ли поддерживаемое. Визуально различия проектов на React и JQuery со временем сохраняются, а вот developer experience с точки зрения трудозатрат на поддержку становится примерно одинаковым.

За лесом кнопок, эффектов и пропсов не разглядеть сценария

JavaScript на то и script, что на нём хорошо писать пользовательские сценарии. React - отличная ui-библиотека. Главное не перепутать. Поддержка пользовательских сценариев описанных через ui-библиотеку - для сильных духом.

Привожу пример. Пожалуй самый распространённый случай - это извращенная интерпретация принципа DRY. Теперь поподробнее: речь идёт про случаи, когда имеется чёткий триггер, например, клик по кнопке, ввод текста в инпуте, но сценарий обработки этого триггера находится в useEffect. Почему в useEffect, а не в onClick или onChange? Ну как же, ведь этот же сценарий запускается ещё и при изменении вот того пропса. Не писать же одно и то же дважды.

Мы перестали оперировать понятиями функций и аргументов. Вместо них мы используем эффекты и пропсы

Чем дальше в лес, тем больше дров. Со временем этот useEffect станет "местом силы". Всё больше и больше пользовательских сценариев будут использовать этот хук, массив зависимостей начнёт расти, а внутри хука появятся инструкции if с хитрыми условиями в скобках. Ну и вишенка на торте - понимание, что без хука наподобие usePrevious ничего не заработает. Не всегда usePrevious показатель неправильно выбранного тригера, но в 9 из 10 случаев вам есть о чём задуматься.

Всего два простых правила

  1. кратчайший путь для сценария

  2. изоляция сценария

Кратчайший путь как раз и начинается с выбора правильного тригера. Например, можно сравнить два варианта из сценария проверки на валидность текста. Есть input, есть стейт value и есть стейт isValid.

Сценарий 1:

  1. onChange устанавливает значение value в стейт

  2. затем useEffect реагирует на изменение value, проверяет его на валидность и устанавливает в стейт значение isValid

Сценарий 2:

  1. onChange вызывает обработчик события с аргументом value, который и установит в стейт value и isValid

Не стоит забывать, что фреймворк - это история про инверсию управления. В данном случае сценарий 2 короче сценария 1 не вдвое, а сильно больше. Ведь во втором случае, при выполнении нашего сценария мы не передавали управление react'у. В первом случае react выполнил один лишний рендер, возможно запустил ещё какие-то хуки, хотя нам это и не надо.

Разрывы в пользовательском сценарии - источник неприятностей

Так мы плавно подходим ко второму пункту - изоляции. Допустим в компонент приходит пропс, который также влияет на значение isValid, тогда для того, чтобы развести два этих сценария достаточно просто описать функцию валидации и передать её в useEffect и в onChange.

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

Всё это поможет другим разработчикам не плутать от useEffect'а к useEffect'у по вашему коду, а зацепившись за триггер последовательно "размотать" сценарий.

Обратная сторона

Мы рассмотрели ситуацию, когда логика приложения просачивается в инструменты построения ui. Теперь рассмотрим второй частый случай, когда внутренности ui протекают в модель приложения.

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

О протечке нам просигнализирует появление в сторе (или в верхнеуровневом компоненте) поля, например, popout: { type, data }. Далее в коде можно обнаружить компонент с немаленькой инструкцией switch, который только и ждет, когда в поле popout положат данные. И вот он подбирает нужный компонент (согласно type), передаёт ему data и сценарий продолжается.

Почему такой обрыв нежелателен? Потому что теряется декларативность, а это именно то, почему мы вибирали react изначально. Вручную ставим, вручную подчищаем.

Пока не исчерпаны все возможности данные должны спускаться сверху вниз. И только когда возможности исчерпаны можно отступить

Косательно примера с todo-листом можно поместить компонент popout внутри компонента ячейки с запланированным действием и при нажатиии на кнопку "удалить" показывать popout через портал. Каждая ячейка имеет свой popout, а значит рассказывает максимально короткий и изолированный сценарий. Для простоты можете использовать библиотеку "react-portal" - он прикрепляет содержимое к document.body. Это не плохо подойдёт для всплывающих окон. Для сценариев, где layout сложный и прикрепление компонента к document.body не отвечает потребностям, я написал библиотеку "react-jsx-portal" (ссылка). Вторая часть readme на русском. Я думаю многим она подойдёт.

Теги:
Хабы:
Всего голосов 11: ↑10 и ↓1+12
Комментарии73

Публикации

Истории

Работа

Ближайшие события

27 августа – 7 октября
Премия digital-кейсов «Проксима»
МоскваОнлайн
19 сентября
CDI Conf 2024
Москва
20 – 22 сентября
BCI Hack Moscow
Москва
24 сентября
Конференция Fin.Bot 2024
МоскваОнлайн
24 сентября
Astra DevConf 2024
МоскваОнлайн
25 сентября
Конференция Yandex Scale 2024
МоскваОнлайн
28 – 29 сентября
Конференция E-CODE
МоскваОнлайн
28 сентября – 5 октября
О! Хакатон
Онлайн
30 сентября – 1 октября
Конференция фронтенд-разработчиков FrontendConf 2024
МоскваОнлайн
3 – 18 октября
Kokoc Hackathon 2024
Онлайн