Как стать автором
Обновить
20
0
Павел Богатырёв @PFight77

Web-developer

Отправить сообщение

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


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

Обертка — это не более чем синтаксический сахар для рендеринга других компонент, поэтому не будет зазорным объявить в ней все свойства, которые есть у компонентов которые она рендерит. В описанном случае, если эти три формы отличаются только надписями, достаточно будет одной обертки которая принимает параметрами заголовок и текст кнопки.

Да, Вы все правильно поняли и правильно написали. Дополню только, что обертка должна быть простая, чтобы "разобраться, что она рендерит" было легко. Все компоненты должны быть такими, чтобы их замена выглядела привлекательнее, чем изменение. Изменение сопряжено с регрессиями, а замена с копипастой. Копипаста не должна казаться достаточно страшной, чтобы она была привлекательнее борьбы с регрессиями.

SOLID подход не простой, поэтому использовать его везде — дорого. Вы можете предложить что-то такое же стабильное но более простое? В примере с формой в другой ветке я не увидел у Вас ничего нового — просто компоненты передаются через пропсы. Или я чего-то не понял?

То есть, в определении формы объявлены некоторые слоты, которые имеют значение по умолчанию и которые можно заменить? Очевидный недостаток такого подхода — нельзя добавить что-то в форму, что там не объявлено. Но в целом да, передавать компоненты через пропсы один из вариантов.

Ну и да, Name тоже можно обернуть в div. Если используется обертка, которая сама создает Name (кстати да, обертки тоже нарушают принцип D, поэтому их нужно использовать осторожно), то эту обертку можно заменить на ее содержимое, и таки обертнуть Name. То есть, общий принцип простой — если не устраивает компонент, просто копируешь его исходники (чем меньше компоненты, тем меньше приходится копировать). Если такое потребовалось дважды и более, есть смысл создать новый компонент.

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


В целом, я считаю что конкретные компоненты вообще не стоит писать по SOLID, даже если они повторно используются и требуют адаптации. Если такая ситуация возникла, то лучше извлечь из этого конкретного компонента повторяющуюся часть в абстрактные, универсальные компоненты (не привязанные к предметной области), и повторно использовать их. Просто потому что всегда лучше прорабатывать по SOLID универсальные компоненты, чем компоненты которые нужны только для данного проекта.

В примере из доков нарушен принцип D, и поэтому этот пример вообще никак не связан со статьей (довольно распространненный паттерн, кстати). Там UserInfo сам принимает решение о рендеринге Avatar, поэтому вызывающий код не может подменить Avatar на что-либо еще, не изменив UserInfo. Только соблюдение всех 5 принципов дает тот эффект, о котором я говорю — возможность заменять компоненты, но не изменять.


По поводу ScrolledToNameCommentFormWithGreenButtons, проблема, конечно есть. Но не нужно создавать новый компонент, если он используется только один раз. Просто замените его на div. Вот если у Вас в пиложении будет 2-3+ случаев, где нужно будет скролить до Name с зеленой кнопкой, то да, такой контрол стоит создать. Но обычно, есть общее правило, и есть единичные исключения.

Пока мне не удается убедить руководство выложить наши повторно-используемые компоненты в open-source. Но я над этим работаю: )

В целом да, если мы абстрагируемся от реальных DOM-элементов, и используем какие-то компоненты, то мы не можем использовать все возможности js и html — только те, которые предусмотрены этими компонентами. Но суть подхода в том, что если нам не хватает возможностей какого-либо компонента, то должно быть легко заменить его. Например, на обычный jsx. Простота замены обеспечивается принципами SOLID, и особенно принципом S — простотой самих компонентов — вам нужно переписать (продублировать) только маленький простой кусочек кода (нужный компонент), тогда как всю остальную логику можно реализовать стандартными компонентами, функционал которых нас в данном случае устраивает.


Применительно к описанному случаю самое простое решение — обернуть форму в простой div, прицепиться к нему через ref и скролить уже до него.

Если это компонент приложения, то есть он существует в единственном виде (как похоже из описания), то заморачиваться с SOLID тут нет смысла. SOLID нужен для компонентов, которые используются в разных контекстах, меняя свой вид в зависимости от конкретной задачи.

В статье говорится про компоненты-обертки, это именно оно. И да, городить новый droplist2, чтобы не трогать. Ну, на самом деле выбор, конечно, всегда есть. Просто изменение droplist это боль — нужно проверять что ничего не ломаешь. Ты выбираешь — словить эту попа-боль, или просто сделать другую обертку. Вообщем, жизнь боль в любом случае: ))

Можно сделать droplist(opts) обертку в дополнение к этим 8 компонентам, если есть острая на то необходимость (он будет просто создавать droplistCheck, droplistMS и т.д.). Только этот droplist не должен меняться.


Ну а в целом да, будет 8 компонентов. Бойлерплейта в этом подходе много, это факт. Именно поэтому его нужно использовать только там, где это нужно.

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

Могу предположить, что вариантов не 8. checkMode очевидно не имеет смысла для input type="text", также как и multiSelect. Опишите, пожалуйста, подробнее задачу (что значат эти опции). Нужно ли динамически (на основе каких-то данных) выбирать соответствующую опцию, или нужный вариант известен на этапе написания кода?


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

Круто, рад это слышать от автора того самого доклада!

Вы путаете повторно используемые компоненты и компоненты приложения. form, container — это повторно используемые, а formHTML — это код компонента приложения, он не используется повторно. Он реализует конкретную фичу в единственном экземпляре. Вот это условие overlay ? нужно только в том случае если Вам нужно динамически менять поведение (показывать/не показывать) overlay. Обычно такой динамики не нужно, и если компоненту не нужен overlay, то он просто его не использует.


p.s. SOLID как раз об этом. Но если у вас много динамической логики (какие-то настройки), то тут да, где-то эти if-ы должны появиться.

Смотрите, когда мы просто передаем любой компонент — мы уже задаем некоторый интерфейс, и родитель что-то о своих детях знает. В React он знает что дети — react-компоненты (они имеют функцию render и др.). Если Form потребует чуть более специфичный интерфейс для детей (не только функция render, но и еще функция validate), то концепции в целом это не нарушит. Просто создаст некоторые ограничения по использованию Form.


Чтобы немного материализовать приведения, давайте приведу конкретный пример. Мы написали простейший диалог, и использовали его где-то в фиче А, следующим образом:


ShowDialog(title, content);

Потом мы начали работать над новым требованием, и нам понадобился диалог без затемнения фона. Мы добавили необязательный параметр showOverlay, и использвали его в фиче Б так:


ShowDialog(title, content, false);

Но по невнимательности в коде ShowDialog эту опцию реализовали следующим образом:


 ShowDialog(title: string, content: string, showOverlay?: boolean) {
    // ...
    if (showOverlay) {
        // render overlay
    }
}

Пример банальный, конечно, но суть думаю понятна — в фиче А overlay тоже пропал. Просто мы забыли сделать значение по умолчанию true, и поломали другую часть приложения. Хорошо если тестировщики протестили сценарий А и заметили ошибку. Хорошо если изменения заметные и в проявляются в простых сценариях. Но на практике ошибка может возникнуть в каком-нибудь хитром сценарии в делком углу приложения. Вот эта постоянная опасность, что ты меняешь часто испльзуемый компонент и всегда рискуешь что-то сломать. Приложение становится хрупкое, его трудно развивать, много времени уходит на багфикс и полное регрессионное тестирование.


Если использовать подход описанный в статье, то добавление новых фич гарантированно никак не повлияет на ранее реализованные фичи (по крайней мере на уровне компонент).

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


Взаимодействие (вроде валидации) — одна из самых сложных тем в этом подходе. Допустим, что html-валидацию мы не можем примнить, и нам нужна кастомная. Варианты тут следующие:


  1. Вынести все взаимодействие в вызывающий код. То есть, тот кто собирает форму подписывается на onSubmit, проверяет там значения полей, и если нужно подсветить какое-то поле, передает ему параметр invalid=true, или добавляет новые компоненты, которые рисуют выделение и показывают сообщение. Обычно, именно этот подход и используется. Допустим, выше по клику на FormCloseButton по умолчанию ничего не происходит. Нужно самим подписаться на клик, и самим закрыть форму (передать isOpen в Form).
  2. Сделать обертку, которая будет генерировать некоторые стандартные формы, и добавлять к ним стандартную валидацию, как описано в 1. Этот подход опасен тем, что мы начнем менять эту обертку. Если обертка часто используется, то она не должна меняться.
  3. Предъявить какие-то требования к дочерним компонентам. Form может потребовать, чтобы дочерние компоненты были не произвольными, а реализовывали определенный интерфейс (имели функцию validate, например). Тогда форма сможет пробежаться по children и выполнить валидацию.
  4. Использовать общий контекст. Мы создаем некоторый объект (контекст), который передаем в Form, и во все дочерние компоненты-инпуты. Каждый компонент умеет работать с контекстом (это часть его интерфейса). В контексте есть некоторый механизм, через который обеспечивается взаимодействие. В первом приближении это архитектура Flux.

Информация

В рейтинге
Не участвует
Откуда
Орел, Орловская обл., Россия
Зарегистрирован
Активность