Pull to refresh

Comments 60

Из всех пяти перечисленных в начале плюсов, выделил для себя только один, последний, но после прочтения стало понятно, что мне, пишущему только под вэб, предлагают полюбить cssinjs потому, что кто-то, наверняка 0,,,00000%, пишет на react native. Получается что 0,001% разработчиков, которые решают каждый день проблемы, которые по другому решить невозможно, решили что теперь всем нужен их cssinjs. В большинстве случаев причины надуманы. Вместо css нужно загрузить столько же js + кавычки + сам cssinjs.
UFO just landed and posted this here
Вы невнимательно статью читали. Еще с первых строк звучали слова о модульности, об удобстве с точки зрения архитектуры приложения и ускорении разработки и загрузки-отрисовки.
Я тоже был против этой идеи изначально, но сейчас встал на сторону автора, потому что это удобно мне, как разработчику.
Ну вот лично я никогда не сталкивался с проблемой перекрытия идентификаторов в css. А размер загружаемого css, при правильном подходе к сборке, будет, если не меньше, то точно не больше, чем c inline (который как раз увеличивает размер) или созданию из js. Понимаете, все хотят быть лучше и наверняка мечтают что в будущем, технологии смогут сделать нас совершеннее, как вид. Но если это спроецировать на конкретную проблему, то окажется, что вместо стильного, умного, многофункционального костюма, как у супергероев, с Вас сдерут кожу и кости до мяса и вкрутят дрелью стальные рельсы. Есть разница? Вот также и с css. решать проблему с помощью сборщиков, означает создать костюм супер героя, то есть не вмешиваться в процесс — внутренности, в которые предлагает лезть jsincss.

Ну вот смотрите, пример из жизни. Педалим мы значит некую отчетность на реакте. Все красиво, css-модули, никаких стилей в js. И тут приходит такой менеджер и говорит: "А мы можем наши красивые контролы/таблички/графики отрендерить в pdf?". И мы такие "Конечно мож… Упс". Нет не можем, ибо css. А могли бы, ибо есть рендереры для css-in-js.


Edit: фантом не предлагайте, бьет рендеринг.

UFO just landed and posted this here

Не путайте @media print с автоматической генерацией pdf на бэкенде.

UFO just landed and posted this here

Вы чего тут беситесь? Какая поделка? На ваш любимый css никто не наезжает.

А могли бы, ибо есть рендереры для css-in-js.

Рендереры в pdf? И не бьют рендеринг?

А если не видно разницы — зачем платить больше? :-)

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

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


и загрузки-отрисовки

Загрузка отрисовка в случае процессинга шаблонов в процессе сборки будет даже выше. Если вам нужна оптимизация, можно даже сделать инлайн-стиль (там где это возможно; так делают под низкопроизводительные платформы), и всё будет еще быстрее, потому что в таком случае ни JS, ни каскадности классов не будет, и на браузер будет абсолютный минимум нагрузки.


Поэтому, судя по всему, такое решение (в статье) вызвано лишь стеком.


Мои коллеги работали с БЭМ — имхо, это монстр, с которым можно либо работать на его условиях (БЭМ-стек), либо будешь собирать море граблей. В данном случае, возможно, это решение является одним из таких шагов, чтобы на БЭМ было удобно работать, но в обычных проектах CSS в JS не нужен, это плохая практика.

Для модульности есть shadow dom, вообще использование веб компонентов решает большинство из озвученных выше проблем.
Я не сторонник CSS-in-JS. Сейчас попробую объяснить почему.
Стили и html могут писать «низкооплачиваемые» участники процесса разработки, типа верстальщиков/дизайнеров.
Отверстав по стайл гайду все возможные состояния компонентов, они могут передать свою работу далее программисту, который привяжет внешнее состояние сверстанных компонентов к модели приложения/сайта.

Например:
Допустим у некой кнопки есть два состояния (нажата — зеленый бэкграунд, отжата — красный). Дизайнер написал стили для каждого состояния и повесил их на разные селекторы. Программист привязывает эти состояния к событиям в системе и при возникновении условного события buttonOn вешает на компонент соответствующий ему класс.

Как из этого всего можно сделать модули?
Тут необходим подход по типу Vue:
Помещаем в один файл с расширением .component разметку на html/jade, стили на css/scss, логику на js. Все это лежит тремя блоками в тегах div, style, script. Далее специальный сборщик все это обрабатывает и аккуратно раскладывает по полочкам: стили добавляет в css-файл, разметку подставляет в html и скрипты добавляет в js-файл.

Все просто и логично: верстальщик создал свою часть компонента, а программист — свою. И никаких десятков библиотек и препроцессоров в зависимостях. А то у React-сообщества уж сильно тяга к овер-инжинирингу проявляется)

Вот таким я вижу будущее компонентной разработки)
будущее, где один компонент типа кнопки пишут несколько человек :)
Вполне неплохое будущее)
Фронтендеры часто жалуются на обилие технологий, которые надо изучать. Мой подход позволяет им, при желании, отстраниться от нюансов CSS и HTML и позволить верстальщикам самим писать хаки для IE6 внутри стилей, а сеошникам писать в HTML свою микроразметку для поисковиков. Освободившееся время они могут потратить на тусовки и развлечения.

В моем будущем программист — свободный человек, который не беспокоится о том, что вышел очередной фреймворк. В будущем от Facebook и Google ему уготовано лишь «eat, sleep, code, repeat»))

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

к чему столько сложностей, давайте просто будем писать стили как мы привыкли на css, less, sass и использовать css modules, каждый может работать в своем файле, и не важно будь это react или vue или еще что-то

import theme from './theme.scss'

function Button() {
    return <button className={theme.button} />
}
UFO just landed and posted this here
В ангуляре из коробки идёт изоляция стилей компонента. В двух разных компонентах на одной странице могут использоваться разные по стилям классы, но с одинаковым именем и при этом они друг на друга не будут влиять. И самое главное, все пишется в привычных файлах CSS,scss,stylus. Почему бы не применить этот подход, который отлично работает?
В двух разных компонентах на одной странице могут использоваться разные по стилям классы, но с одинаковым именем

Что выносит мозг программисту при отладке.

Что-то невероятное вообще написано: "css классы с одинаковым именем и разными стилями"? Или имеется в виду класс из языка программирования то тогда наверно надо говорить об объекте, т.к. класс только характеризует каким может быть объект, но у объекта не может быть имени (если мы не дадим ему такого свойства).

Ангуляр составляет селектор из его имени и рандомного аттрибута типа .btn[asd234]. Так что может быть 2 компонента с селектором .btn, но стили будут разные из-за аттрибута.


Это все невероятно доставляет, ибо хваленая инкапсуляция стилей (в отличие от css-модулей) работает только наполовину и любой такой класснейм в глобале протечет в несчастную кнопку. Думаю, что вы догадались по имени селектора кнопки, какой именно движок протекает?

Вообще такое неизбежно при разработке подсистем группа разработки может именовать внутренние классы как будет удобно. Для этого в c++ используется namespace а в js да разные классы могут быть объявлены в разных scope иногда могут совпадать имена, при этом сами они будут разными. Но они должны использоваться только внутри своих подсистем и не быть доступными снаружи для пользователя данной библиотеки или подсистемы. Если они должны быть видны снаружи они обычно должны иметь общий префикс в имени. При отладке обычно такие классы используются внутри своих подсистем и отлаживаются при отладке своих подсистем и покрываются тестами. Поэтому при отладке системы которая использует эти подсистемы на прямую работать с такими внутренними классами не должно быть необходимости.

Ну вот и представьте: у вас есть диалог, запиленный одной группой людей, в нём форма, запиленная второй группой людей, в нём календарик, запиленный третьей группой людей, вам нужно разобраться почему календарик распирает диалог, а каждая из этих 3 труп людей посчитала своим долгом дать своим блокам лаконичные имена вида "main", "box" и тому подобные. В итоге вас в стилях: .main[erucqi], .main[ifdofi] и .main[reoo]. Счастливой отладки.

Группы могли бы всё назвать по разному, для этого им потребуется общий реестр. Если бы был реестр то имена были бы не .main[erucqi], .main[ifdofi] и .main[reoo] а например .dialog_main, .form_main, .calendar_main. То есть при отладке разница будет лишь в именах.


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


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

Группы могли бы всё назвать по разному, для этого им потребуется общий реестр.

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


Напрашивается возможность в отладчике задать именам классов определяемые пользователем псевдонимы (alias)

Чтобы ещё больше всех запутать?

Кто-то приходит, кто-то проходит мимо, это дело вкуса.


Механизм css так устроен что одно на другое очень сильно влияет, один только clearfix чего стоит. Одна из причин почему появился flex. Всё собрано в один глобальный css с глобальными именами. Это проблема вызвана самим css, в котором нет пространства имен. Здесь рассмотрены разные методы решения этих проблем. Их не навязывают, можете их не использовать это дело вкуса.


А то что у кого то в отладчике прописано временно для отладки показывать .dialog_main вместо .main[erucqi] никого другого не запутает.

ММеханизм css так устроен что одно на другое очень сильно влияет, один только clearfix чего стоит.

Вы не смешивайте тёплое с мягким. При чём тут конфликты имён?


Это проблема вызвана самим css, в котором нет пространства имен.

Пространства имён есть везде, где есть имена. Ваши префиксы "dialog", "form" и "calendar" — пространства имён в чистом, не замутнённом синтаксическим сахаром, виде.


в отладчике прописано временно для отладки показывать .dialog_main вместо .main[erucqi] никого другого не запутает.

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

Вы не смешивайте тёплое с мягким. При чём тут конфликты имён?

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


Всё в комплексе разрабатывалось и привело к тому что есть и по отдельности нет смысла рассматривать. Вы же описали задачу в которой есть конфликт имён и влияние элементов которые распирают. Если бы не распирали то и проблемы конфликта имен бы никто не заметил. Вот и не смешивали бы сами.

> вам нужно разобраться почему календарик распирает диалог, а каждая из этих 3 труп людей посчитала своим долгом дать своим блокам лаконичные имена вида «main», «box» и тому подобные. В итоге вас в стилях: .main[erucqi], .main[ifdofi] и .main[reoo].

Все дом-ноды с кастомными стилями маркируются соответствующим атрибутом. Такой ситуации, когда непонятно, какой класс откуда прилетел — возникнуть в принципе не может (разве что вы не можете понять откуда вообще отрендерился рассматриваемый вами кусок dom, но тогда вам уже ничего не поможет).

Каким атрибутом? Чтобы понять кто что отрендерил и нужны глобально уникальные имена. Или вы предлагаете интерпретировать код у себя в голове, пытаясь понять какой из элементов к которому из нескольких одноимённых компонент относится?

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

> Чтобы понять кто что отрендерил и нужны глобально уникальные имена.

Зачем? Если вы знаете что нода от компонента Х — то у нее стили именно от этого компонента.

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

Не могу себе даже в теории представить ситуацию, когда непонятно к какому компоненту относится инспектящаяся нода. Без каких-либо интерпретаций в голове. Можете привести пример?
Зачем? Если вы знаете что нода от компонента Х — то у нее стили именно от этого компонента.

Как понять, что она от компонента X?


Не могу себе даже в теории представить ситуацию, когда непонятно к какому компоненту относится инспектящаяся нода.

Трансклюдами в ангуляре или компонентами высшего порядка в реакте не пользовались? А есть фреймворки и с более динамичной компоновкой...

> Как понять, что она от компонента X?

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

> компонентами высшего порядка в реакте не пользовались?

Это же известный антипаттерн. В любом случае, мы ведь не про реакт, там все, действительно, совсем плохо — стили инлайнят (привет технологиям десятилетней давности), компоненты сильно дробят, за неимением адекватных средств, действительно, приходится использовать HOC с другими подобными костылями и т.д…

> Трансклюдами в ангуляре

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

> А есть фреймворки и с более динамичной компоновкой…

Структура документа заранее известна, любой компонент врапнут в соответствующий тег., имена хост-элемента проставлены. Все еще не могу представить такой ситуации, даже с динамическими компонентами. Даже если попробовать добиться такой ситуации специально.
Это же известный антипаттерн.

Может мне хоть кто-нибудь это объяснить?


стили инлайнят

давно уже не инлайнят


компоненты сильно дробят

что плохого?


за неимением адекватных средств, действительно, приходится использовать HOC

Раскажите, пожалуйста, какие адекватные средства вы имеете в виду, и почему за неимением оных "приходится использовать" HOC. И почему, собственно, HOC плохи?

> давно уже не инлайнят

И как тогда решается проблема с инкапсуляцией классов?

> что плохого?

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

> Раскажите, пожалуйста, какие адекватные средства вы имеете в виду

Трансклюд, директивы

> И почему, собственно, HOC плохи?

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

При чем тут инкапсуляция? Под "давно уже не инлайнят" я имел в виду CSSOM и экстракт в css-файлы. Или вы о чем?


Если дробления нет — для той же задачи достаточно одного мимолетного взгляда.

Ну я даже не знаю… Вы за трех-экранные полотна маркапа? Если нет, то где тогда грань? И как же декомпозиция, как же переиспользуемость?


Трансклюд, директивы

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


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

Не понимаю, о чем вы.

> При чем тут инкапсуляция?

При том, что мы ее, вроде, тут обсуждаем? Вот я повесил на дом-ноду какого-то компонента класс, описал для него стиль, как обеспечивается изоляция этого стиля?

> Под «давно уже не инлайнят» я имел в виду CSSOM и экстракт в css-файлы. Или вы о чем?

При чем тут экстракт? Я говорил об использовании. Под «инлайнингом» подразумевался подход, эквивалентный styled components, когда вы тем или иным способом указываете стиль для конкретного дом-элемента, в противовес классическому css подходу с указанием стиля для селектора, то, что сейчас подразумевается под css-in-js. Если вы под css-in-js подразумеваете просто генерацию стилей на ходу — то так оно и в ангуляре css-in-js тогда, там после компиляции никаких .css не остается.

> Ну я даже не знаю… Вы за трех-экранные полотна маркапа? Если нет, то где тогда грань? И как же декомпозиция, как же переиспользуемость?

Грань определяется золотой серединой, как и всегда. Трехэкранные полотна — плохо, двухстрочные компоненты — тоже плохо (и неизвестно, что хуже). Разумная декомпозиция (то есть, семантическая, когда необходимый кусок выделяется по внешним по отношению к коду соображениям) — хорошо и ведет к переиспользуемости. Излишнее дробление, к слову, к ней не ведет, т.к. бессмысленный кусок кода вы больше одного раза использовать не станете.

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

Ну смотрите, в ангуляре есть и HOC и директивы. Все используют директивы и не используют HOC. Вывод очевиден — если людям дать нормальный инструмент, то HOC выбрасывается на помойку.
Вот я повесил на дом-ноду какого-то компонента класс, описал для него стиль, как обеспечивается изоляция этого стиля?

Эээ, а откуда вы это класс взяли? Из глобала? Ну так какая тогда инкапсуляция? Если из css-модуля — эти стили заинкапсулированы в компоненте, который импортирует этот css-модуль. Пусть даже и в глобале все так же, но с уникальным селектором.


Грань определяется золотой серединой

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


в ангуляре есть и HOC

Что, простите?


Все используют директивы

Все используют директивы, так как это единственный вариант подмешать что-то компоненту так, чтобы не было обертки в доме.


Послушайте, у меня нет никакого желания опять поднимать эту тему и устраивать тут недельную разборку. Я вас спрашивал, чем плохи HOC, не надо опять соскакивать в обсуждение angular vs react.

> Пусть даже и в глобале все так же, но с уникальным селектором.

С каким селектором?

> А где эта середина?

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

> Что, простите?

То, простите. HOC — неотъемлемая часть ангуляра, например, на каждый класс компонента применяется HOC «Component».

> Все используют директивы, так как это единственный вариант подмешать что-то компоненту так, чтобы не было обертки в доме.

HOC тоже не генерит оберток (откуда?). Но используют директивы.

> Я вас спрашивал, чем плохи HOC, не надо опять соскакивать в обсуждение angular vs react.

Я вам привел пример ситуации, в которой есть как HOC, так и другие инструменты. В результате люди используют другие инструменты. Мне вывод кажется очевидным. Мне кажется, что логически невозможно заявлять о преимуществе HOC перед директивами, не объяснив, почему в ангуляре люди выбирают использовать директивы.
С каким селектором?

Что-нибудь вида .Button__element_34732, как настроите.


Я же описал.

Это-то и понятно. Если перечитаете мой предыдущий комментарий, поймете, к чему такие вопросы.


на каждый класс компонента применяется HOC «Component».

Ух ты чушь какая. У меня складывается ощущение, что вы не понимаете, что из себя представляет higher order component. HOC — это компонент, принимающий в качестве "аргумента" другой/другие компоненты и инстанцирующий/рендерящий их, а не просто декоратор.


Вот это HOC.


const List = ({Item}) => <ul><Item>item</Item><ul>;

Вот это HOC.


const HOC = () => (Target) => {
  return class Wrapped extends Component {
    static displayName = `Wrapped(${Target.name})`;
    render() {
      return <Target {...this.props} addSomeProp={true}/>;
    }
  }
};

Да, они разные, и, если честно, первый вариант мне больше кажется HOC, нежели второй.


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


@Component({
  selector: 'foo-foo',
  template: 'i\'m a foo'
})
class Foo {
}

HOC тоже не генерит оберток (откуда?). Но используют директивы.

См. предыдущий пункт

> Это-то и понятно. Если перечитаете мой предыдущий комментарий, поймете, к чему такие вопросы.

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

> HOC — это компонент, принимающий в качестве «аргумента» другой/другие компоненты и инстанцирующий/рендерящий их, а не просто декоратор.

Во-первых, HOC — не компонент. Это функция. Функция, которая принимает компонент (функцию или класс) и возвращает компонент (функцию или класс). В каком месте это не «просто декоратор»?

> Но уж вот это никак HOC не является, это обыкновенная аннотация, помогающая дубовому шаблонизатору сообразить какую модель инстанцировать при встрече нужно селектора.

Это не аннотация, это функция, которая принимает класс и возвращает класс. Как-нибудь так:
const Component = (annotation) => (target) => {
    return class Wrapped extends target {
        ...
    }
}


> См. предыдущий пункт

Практически любую директиву можно переписать в HOC наподобие вашего второго примера. Но так никто не делает. Почему?
Реакт у вас требует выделять компоненты, чтобы код не был чересчур вырвиглазен. Ангуляр не требует.

Чего? Полотна разметки и там и там одинаковые и степень вырвиглазности в отвратного DSL ангуляра повыше будет. Хотите выделяйте компоненты (и там, и там), не хотите — не выделяйте (и там, и там).


Во-первых, HOC — не компонент. Это функция. Функция, которая принимает компонент (функцию или класс) и возвращает компонент (функцию или класс). В каком месте это не «просто декоратор»?

HOC — higher order Component. И именно это показывает List. А дальше я специально уточнил, что я не совсем согласен с зародившейся в экосистеме реакта называть фабрики компонентов компонентами высшего порядка.


Это не аннотация, это функция, которая принимает класс и возвращает класс.

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


Практически любую директиву можно переписать в HOC наподобие вашего второго примера. Но так никто не делает. Почему?

Нет нельзя, так как у вас появится dom-обертка. Поэтому и не делают, потому что нельзя. А сама идея этих директив противоречит идеи разделения вьюхи и модели. Поведение модели должно определяться и расширяться моделью, а не нагромождением заклинаний в маркапе.

> Чего? Полотна разметки и там и там одинаковые

Нет, не одинаковые. В реакте у вас map'ы и ?:, которые делают код совершенно нечитабельным. В итоге приходится выделять содержащий подобные вещи код в отдельные функции. Которые иначе были бы не нужны.

> и степень вырвиглазности в отвратного DSL ангуляра повыше будет

Даже плохой DSL почти всегда лучше универсального языка. Именно по-этому DSL создаются (ведь это требует дополнительной работы), именно по-этому от jsx-подходов на бекенде отказались давным-давно.

> HOC — higher order Component.

HOC — не компонент. Как бы он ни назывался. Он не обладает свойствами компонента, его нельзя использовать как компонент. Обратите внимание на аналог — HOF. HOF — по факту _является_ ф-ей, обладает св-вами функции, может использоваться как ф-я. Видите разницу? В любом случае, давайте не будем заниматься спором о терминологии, мы говорим о конкретной сущности, а как ее называть — дело десятое.

> Ну по вашей логике мне нужно каждый мой «компонент» обернуть в эту функцию, чтобы движок понял, что это «компонент».

Нет, это не так, конечно. Любой класс является классом компонента сходу, а Component — лишь связывает этот класс с его видом, добавляя во внешнюю конфигурацию соответствующую информацию. Сообщает движку, что «если ты увидишь этот селектор то надо создать данный вид и привязать к указанному компоненту». У одного компонента может быть много видов, к слову. Вы же сами в курсе, что аннотации из Component не наследуются — потому что они не являются св-вами полученного класса, и вообще к этому классу отношения не имеют. Иными словами, класс компонента в ангуляре не содержит ф-и «render». Эта ф-я живет отдельно от компонента и к нему не привязана. С точки зрения ментальной модели реакта это трудно понять, т.к. в реакте как раз ф-я «render» сама по себе уже является компонентом (вид = модель). Но фреймворки разные, ничего удивительного. Надо эту разницу в рассуждениях учитывать.

> Нет нельзя, так как у вас появится dom-обертка.

При использовании HOC не появляется дом-обертки. Откуда ей взяться? Напоминаю, что директивы в ангуляре не используются для генерации дом, они используются для подмешивания поведения. То есть у вас уже есть компонент и ваша директива будучи к нему примененной бэкграунд меняет по таймеру. Все то же самое можно сделать с HOC и никаких оберток не будет, им неоткуда взяться. Но используют в таких случаях директивы, а не НОС.

> Поведение модели должно определяться и расширяться моделью, а не нагромождением заклинаний в маркапе.

В маркапе никакой модели нет. Модель — класс компонента. Он существует независимо от маркапа, маркап — существует независимо от класса компонента. Один маркап можно использовать с разными моделями. Одну модель можно использовать с разными маркапами. Связывание маркапов с моделями производится на внешенм этапе конфигурирования. Внешнем в том смысле, что ни сам маркап, ни модель, это конфигурирование не затрагивает. Вас смущает тот факт, что дефолтный вариант работы — это аннотация на классе. Но это просто дефолт, удобное стандартное поведение, которое подходит в большинстве кейзов и потому специально реализовано.
В реакте у вас map'ы и ?:, которые делают код совершенно нечитабельным.

Все, прекратите, каша из звездочек, скобочек и "коробочек" уж никак не лучше обычных языковых конструкций, субъективщина чистой воды.


Он не обладает свойствами компонента, его нельзя использовать как компонент.

Вот что вы мне тут рассказываете


const List = ({Item, items}) => (
  <ul>
    {items.map((item, i) => (
      <Item key={i}>{item}</Item>
    ))}
  </ul>
);

const Item = ({children}) => <li>{children}</li>;

const result = <List Item={Item} items={[1,2,3]}/>;

Компонент? Компонент. Высшего порядка? Высшего.


Модель — класс компонента.
Связывание маркапов с моделями производится на внешенм этапе конфигурировани

Это все просто прекрасно. Только меня смущает не это, а то, что добавление поведения к модели (классу компонента) происходит из маркапа другого компонента. Именно так директивы и вешаются, или есть еще какой-то способ их использовать?




И вы так и не объяснили, чем плохи HOC.

> Все, прекратите, каша из звездочек, скобочек и «коробочек» уж никак не лучше обычных языковых конструкций, субъективщина чистой воды.

Это объективный факт. Сообщество много лет назад давным-давно признало, что генерить портянки руками — ад и погибель, и все перешли на шаблонизаторы в том или ином виде. То, что на волне хайпа фейсбуку удалось продать наивным, не нюхавшим пороху пионерам от фронтенда фреймворк, предназначенный для портирования протухшего легаси-кода с php на js — просто исторический казус.

Тот факт, что jsx нечитаем — подтверждают сами люди, которые пишут на jsx, когда выделяют ветки тех же ?: в отдельные ф-и.

> Высшего порядка? Высшего.

Нет, конечно. Это обычный компонент, который возвращает обычный кусок ДОМ. HOC же возвращает компонент, а не кусок ДОМ.

> Только меня смущает не это, а то, что добавление поведения к модели (классу компонента) происходит из маркапа другого компонента.

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

И, в итоге, так и не получается ответить на вопрос: если в ангуляре есть и директивы, и HOC, которые могут выполнять одну и ту же задачу, и HOC решают эту задачу лучше, то почему все используют директивы?
что генерить портянки руками

Ну так не генерите портянки. Декомпозиция, все дела, я уже устал это повторять.


То, что на волне хайпа фейсбуку удалось продать наивным, не нюхавшим пороху пионерам от фронтенда фреймворк, предназначенный для портирования протухшего легаси-кода с php на js

О, ну да, ну да


Тот факт, что jsx нечитаем — подтверждают сами люди, которые пишут на jsx, когда выделяют ветки тех же ?: в отдельные ф-и.

Такой же факт подтверждают те, кто пишет вот такой бред:


<div *ngIf=”condition; else elseBlock”>Truthy condition</div>
<ng-template #elseBlock>Falsy condition</ng-template>

Давайте вы не будете выдавать желаемое за действительное, и мы уже наконец закроем тему синтаксиса.


Нет, конечно. Это обычный компонент, который возвращает обычный кусок ДОМ. HOC же возвращает компонент, а не кусок ДОМ.

Давайте вспомним функции высшего порядка, ведь именно по этой аналогии появились компоненты высшего порядка. Так вот, фвп — функция либо принимающая другую функцию в виде аргумента, либо возвращающая другую функцию, либо и то, и то.
Так же и с компонентами, либо принимаем в аргументы, либо возвращаем новый, либо все сразу. Так вот при первом упоминании я описал вам оба варианта: List принимает функцию, Wrapper возвращает.
А dom тут вообще не при чем, это результат выполнения функции (компонента), принимающей другую (другой компонент), то есть первый случай.


Надеюсь, мы это утрясли. Если нет — определение HOF все проясняет.


Никто никакого поведения к модели не добавляет.

А как же @Host в связке с @HostBinding и @HostListener? Как-то все сразу вперемешку становится. Сами же мне говорили использовать директивы для связки тупых компонентов со стором ngrx. И дело тут не в реакте или в "неправильной ментальной модели" а в том, что вместо явного создания нового компонента через HOC с подмешанным поведением, приходится прямо из маркапа обвешивать несчастного дополнительными конструкциями, что-то в него пихающими и слушающими его события.


И, в итоге, так и не получается ответить на вопрос: если в ангуляре есть и директивы, и HOC, которые могут выполнять одну и ту же задачу, и HOC решают эту задачу лучше, то почему все используют директивы?

Еще раз, в ангуляре нет HOC. @Component — это не компонент. Компонент — это результат его выполнения. Так вот результирующий компонент уже никак (почти) не может быть компонентом высшего порядка. Почти — потому-что все же есть механизм динамического инстанцирования, и можно передать класс другого компонента через @Input, но это жутко неудобно и ограниченно. А вот вернуть другой компонент при "вызове" этот уже никак не может.


Так что хватит уже, нет в ангуляре HOC и нет их там бай дизайн ибо шаблонизатор статический, а инструментов для динамики изначально вообще не было, а те что сейчас — кривые.


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

> Ну так не генерите портянки.

А как в реакте не генерить портянки, если другого способа не предоставлено?

> Декомпозиция, все дела, я уже устал это повторять.

То, что вы разделите ручную генерацию портянок на несколько кусков — ничем не поможет. Более того — оно вредит. Потому что мы возвращаемся к началу — из-за искусственного чрезмерного разбиения процесс генерации становится запутанным и в нем сложнее разобраться. Вместо того чтобы посмотреть на шаблон и сразу понять примерно результат, вам надо собрать по кускам все ф-и и проследить логику их работы.

> Такой же факт подтверждают те, кто пишет вот такой бред:

А в чем проблема? код хорошо структурирован, ветки зрительно отделены, логика ловится с простого взгляда. Более того — все это прекрасно скалируется на шаблоны любого размера. Сравните с ?:, где если ветка длиннее двух строк — вы вынуждены ее отделять, потому что иначе код даже выровнять-то по-человечески затруднительно.

> и мы уже наконец закроем тему синтаксиса.

Я не затрагивал тему синтаксиса.

> Давайте вспомним

Ок. Утверждение «HOC является компонентом» — ложно, так как существуют HOC, которые компонентами не являются. В точности так же, как является ложным утверждение вида «Человек — это негр». На этом спор по части терминологии предлагаю закрыть.

> А как же Host в связке с @HostBinding и @HostListener?

Это реализация директивы, а не ее использование. Вы когда директиву используете, то вообще не в курсе, какие там @HostListener внутри. У вас задача — сделать, чтобы компонент мигал. Это свойство вида, которое никак не затрагивает логику работы самого компонента. По-этому информация о том, что компонент — мигучий, расположена в разметке, это вид.

> а в том, что вместо явного создания нового компонента через HOC с подмешанным поведением, приходится прямо из маркапа обвешивать несчастного дополнительными конструкциями

Если бы в jsx можно было использовать компоненты как <Hoc(Component) .../>, не объявляя промежуточных, то большинство бы так и делало. И было бы это таким же обвешиванием из маркапа. И от того, что вы промежуточную переменную создаете — в сущности ничего не меняется.

> Еще раз, в ангуляре нет HOC. Component — это не компонент. Компонент — это результат его выполнения.

Конечно.

> Так вот результирующий компонент уже никак (почти) не может быть компонентом высшего порядка.

Он и не должен. HOC — это Component, а не результат работы Component.

> А вот вернуть другой компонент при «вызове» этот уже никак не может.

Но Component возвращает компонент при вызове. Любой декоратор это делает.

> Никак я не могу обернуть компонент так, чтобы получился новый компонент, рендерящий старый с дополнительными свойствами, без dom-обертки.

В классе компонента ангуляра _нет функции рендер_. По-этому когда вы делаете в ангуляре HOC, то вы никак не меняете разметку и поменять ее не можете — потому что нельзя поменять то, чего нет. HOC могут поменять «логику работы», например — взять обычный компонент и сделать из него мигающий компонент. Прямо как директива. Понимаете? Именно по-этому я сравниваю именно с директивой — потому что в директиве вы не можете переопределить разметку, внутри директивы у вас ровно те же ограничения, что и в HOC. По-этому:

> Так что вопроса как такового нет. Все используют директивы, потому-что по-другому никак.

Очень даже «как». Практически все, что может директива, можно сделать при помощи НОС. Но НОС не используют.

Еще раз — НОС не используют не для «переопределения рендер функции» (это и директивой нельзя), а для тех вещей, который можно сделать директивой. И их же (в основном) можно сделать в НОС.
А как в реакте не генерить портянки, если другого способа не предоставлено?

Молча, как везде. Бьете на компоненты и собираете в композицию.


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

Ну это только вам там кажется. Вы же не пишете (надеюсь) функции/методы по 500 строк?


А в чем проблема? код хорошо структурирован, ветки зрительно отделены, логика ловится с простого взгляда.

Аааааа, вы прикалываетесь? Это же корявое месиво из невнятных конструкций, сплошной синтаксический шум.


Я не затрагивал тему синтаксиса.

Что же это, если не синтаксис разметки?


У вас задача — сделать, чтобы компонент мигал

Мне не интересно это мигание. Это свойство вида и делать его я буду через компонент. Мне нужно забрать из стора данные и запихать в этот компонент так, чтобы это никак не влияло на внешний вид (не было обертки). И сделать это через "HOC" в ангуляре нельзя.


По-этому когда вы делаете в ангуляре HOC, то вы никак не меняете разметку и поменять ее не можете — потому что нельзя поменять то, чего нет. HOC могут поменять «логику работы», например — взять обычный компонент и сделать из него мигающий компонент.

Так, надоело, давайте пример HOC WithBlink, из обычного компонента делающего мигающий. Учтите, что базовый компонент уже аннотирован @Component, а WithBlink оборачивать нельзя, он же "принимает компонент — возвращает компонент"


потому что в директиве вы не можете переопределить разметку,

Забавно, но в реакте я могу это сделать. Внутри HOC я могу пробежаться по результату выполнения оборачиваемого компонента и делать вообще что душе угодно. Догадываюсь, что вы скажете, что это "неправильная ментальная парадигма" и так делать нельзя, фу фу фу.


Еще раз — НОС не используют не для «переопределения рендер функции» (это и директивой нельзя), а для тех вещей, который можно сделать директивой. И их же (в основном) можно сделать в НОС.

Мне кажется, вы лихо сели в оборону и съехали на "HOC" в ангуляре, тогда как


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

ну и самое важное


Это же известный антипаттерн.

жду обоснований, пока только вода

> Бьете на компоненты и собираете в композицию.

Ну так мы возвращаемся к началу — в случае с шаблонами не бью, а в случае с jsx — вынужден бить, когда длоя этого по факту нету никаких причин кроме «иначе код вырвиглазен». И это чрезмерное разделение приводит к негативному результату, значительно повышая сложность приложения.

> Аааааа, вы прикалываетесь? Это же корявое месиво из невнятных конструкций, сплошной синтаксический шум.

Синтаксис не существенен, это вопрос привычки. В пример можно привести известную картинку о лиспе и скобках. А вот структура кода — важна весьма.
И, насчет синтаксиса — будем честны, в JSX месива никак не меньше.

> Мне не интересно это мигание.

Но именно эту задачу мы и рассматриваем. Еще раз, по порядку. Есть задача: сделать мигающий компонент (и другие задачи подобного класса). В данном случае мы работаем с видом и это свойство вида, а не модели. Решить задачу можно через НОС, можно через директиву. На практике — решают ее через директиву. Почему?

> Учтите, что базовый компонент уже аннотирован Component, а WithBlink оборачивать нельзя, он же «принимает компонент — возвращает компонент»

Откуда эти странные требования? Конечно, вам надо будет применить аннотацию. Ведь возвращаемый класс компонента не имеет ф-и рендер. Как его рендерить-то тогда?

> Мне кажется, вы лихо сели в оборону и съехали на «HOC» в ангуляре, тогда как

Я вам констатирую один простой наблюдаемый факт: есть класс задач, которые в ангуляре решаются как при помощи HOC, так и при помощи директив. При этом люди выбирают директивы. На основании этого я делаю гипотезу: директивы являются значительно более хорошим решением. Альтернативная гипотеза — существую какие-то иные причины. ОЧевидна, одна из этих причин верна. Я этих иных причин не вижу, вы их привести не можете. Отсюда я делаю вывод, что таких причин нет и верна первая гипотеза.

> жду обоснований, пока только вода

«Антипаттерн» — это распространенный подход к решению каких-либо задач, который является по каким-то причинам неудачным. Использование HOC невыразительно, негибко, ведет к повышению связности когда, его усложнению, копипасте и снижению качества кода в целом. Оно нарушает большую часть принципов SOLID. То, что паттерн плох, подтверждается наблюдениями — при наличии альтернативных вариантов решения люди по возможности избегают делать HOC и используют более высокоуровневые, более развитые подходы (например, директивы).

Здесь единственное, что следует уточнить — возможно, НОС не являются антипаттерном именно _в контексте реакта_. То есть, да, ясно, что решение плохое — но точно так же ясно, что плохое решение лучше, чем никакого, а других вариантов в реакте нету. На безрыбье — и рак рыба, что называется.

Но мы же рассуждаем о концепции в целом?
в случае с шаблонами не бью

Вы предпочитаете полотна? Ну фиговый из вас разработчик тогда. И про методы на 500 строк промолчали.


Но именно эту задачу мы и рассматриваем.

Я ее не рассматриваю, это вы к этому миганию прицепились.


Откуда эти странные требования? Конечно, вам надо будет применить аннотацию. Ведь возвращаемый класс компонента не имеет ф-и рендер. Как его рендерить-то тогда?

Ну так не надо говорить тогда, что это HOC. У вас банально функция будет принимать класс и возвращать класс. Поверх которого потом еще и @Component жахнуть надо. И от обертки вы не избавились. И пример не привели. Не можете — не надо спорить.


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

лол какой копипасте? у вас какое-то ну совсем странное мышление. повышение порядка — это повышение уровня абстракции и гибкости и как следствие снижение копипасты.


Оно нарушает большую часть принципов SOLID

В каком месте HOC нарушает хоть что-то?


То, что паттерн плох, подтверждается наблюдениями — при наличии альтернативных вариантов решения люди по возможности избегают делать HOC и используют более высокоуровневые, более развитые подходы (например, директивы).

Ну окей, если вам нравится такая модель общения — в реакте нет директив, потому-что они не нужны, так как есть HOC, выразительные, гибкие, понижающие связность кода, упрощающие его, убирающие копипасту и повышающие качество кода в целом. Как вам?


Но мы же рассуждаем о концепции в целом?

Нет. Мы рассуждаем о HOC в контексте реакта, так как в ангуляре их нет. Есть функции, которые принимаю класс и возвращают класс. Хотите называйте их фвп, как хотите. Но они ни являются компонентами, ни возвращают компоненты. Ни одно из условий для HOC не выполняется.


В общем понятно, какое-то размусоливание, а по делу ничего. Давайте закончим.

> Вы предпочитаете полотна?

При чем тут полотна? Естественно, код разделяется на компоненты. Но семантически, когда это нужно. А когда это не нужно (как в случае искусственного выделения условных веток) — не разделяется.

> Я ее не рассматриваю

То есть вы просто игнорируете неудобные для своей гипотезы факты?

> Ну так не надо говорить тогда, что это HOC. У вас банально функция будет принимать класс и возвращать класс.

Так в ангуляре классы компонентов ничем и не отличаются от обычных классов.

> И от обертки вы не избавились.

От обертки избавляться в данном случае не нужно, потому что ее не будет. откуда вообще вы ее выдумали?

> И пример не привели.

Я пример не привел потому, что вы изначально потребовали надуманные невыполнимые условия. Давайте я потребую привести от вас в реакте аналогичный HOC, который можно будет применять, не объявляя отдельную переменную для результирующего класса. Вы пример не приведете, потому что его написать невозможно, и я объявлю, что НОС в реакте не существует. Глупость же.

> повышение порядка — это повышение уровня абстракции и гибкости и как следствие снижение копипасты.

Это, конечно, далеко не всегда так.

> В каком месте HOC нарушает хоть что-то?

S, O, D — нарушается откровенно.

> Ну окей, если вам нравится такая модель общения — в реакте нет директив, потому-что они не нужны, так как есть HOC, выразительные, гибкие, понижающие связность кода, упрощающие его, убирающие копипасту и повышающие качество кода в целом. Как вам?

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

> Нет. Мы рассуждаем о HOC в контексте реакта, так как в ангуляре их нет.

Они есть. Любая функция, которая принимает класс компоненты и возвращает другой класс компоненты — является НОС в ангуляре. Например, ф-я, которая подмешивает к компоненту «логику мигания». От того, что вы спрятались в домик и закрыли глаза — реальность не изменится.

> Но они ни являются компонентами, ни возвращают компоненты.

Они не являются компонентами в реакте, но являются компонентами в ангуляре. Понятие компонента в ангуляре и реакте — разное. В реакте не существует компонентов в понимании ангуляра (т.к. класс без логики рендера не является компонентом), а в ангуляре не существует компонентов в понимании реакта (т.к. компонент не может содержать логику рендера).

Ну я же чуть выше написал.
Вот у вас в компоненте есть элемент .container, стили к нему, соответственно, будут в селекторе .container[hsagfkj]. Но вот незадача, заказчик захотел свой кастомный бутстрап в виде css. И, вот же незадача, у вашего элемента вдруг от куда не возьмись появились паддинги по бокам...


Держать это все в голове, думая над именами селекторов? Ну так это уже не инкапсуляция, а пародия.

> Но вот незадача, заказчик захотел свой кастомный бутстрап в виде css. И, вот же незадача, у вашего элемента вдруг от куда не возьмись появились паддинги по бокам…

Это проблема реализации (shadow dom эмулирутеся), а не подхода. Перейдут все на нативный shadow dom — проблема сама собой исчезнет.

> Держать это все в голове, думая над именами селекторов?

Зачем? Можно решить эту проблему так, как вы решали бы ее с css-in-js — вместо того, чтобы импортировать свой бутстрап глобально, импортируйте его в каждую компоненту, локально. Все точно так же и с точно тем же результатом.
Ну, первая (вторая) змея адаптивная, а вторая (третья) резиновая
Sign up to leave a comment.