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

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

Писать кнопочки и формочки на 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 на русском. Я думаю многим она подойдёт.

Источник: https://habr.com/ru/post/600035/


Интересные статьи

Интересные статьи

Одним из наиболее важных этапов запуска дропшиппинг-магазина является создание рекламных креативов. Вы можете грамотно подобрать товар, собрать сайт и настроить рекламу, но если ваши креативы не будут...
Довольно часто приходят задачи написать скрипты для Microsoft 365, будь то репортинг или какие-то автоматизации. Как правило, сервисы входящие в пакет M365: Exchange Online, SharePoint Online или Micr...
Зашел сегодня на телдери поискать какой-нибудь подходящий сайт по нужной мне тематике. По запросу совсем немного сайтов выдал, но выдал такой Старый сайт о программирован...
Мне было необходимо делать 2 раза в сутки бэкап сайта на «1С-Битрикс: Управление сайтом» (файлов и базы mysql) и хранить историю изменений за 90 дней. Сайт расположен на VDS под уп...
У некоторых бизнес-тренеров в области е-коммерса и консультантов по увеличению интернет-продаж на многие вопросы часто можно слышать универсальную отмазку — «надо тестировать» или другую (чтобы не...