2017: Автостопом по галактике JavaScript

    Расшифровка доклада Ильи Климова на конференции JavaScript fwdays.


    Мы с вами попробуем отследить некоторые тренды в развитии JS, как сообщества, как движения, в 2017-ом году. Я очень постараюсь избежать оценочных суждений. Хотя кого я обманываю, все равно не получится. И где-то через год вы сможете с радостью открыть эту презентацию на YouTube, и понять, насколько я был не прав.


    Поэтому давайте перенесёмся в 2015 год. Посмотрим, как развивался JS.




    Лично для меня 2015 год в JS прошел под знаком анархии.




    У нас был взрывообразный рост всего, чего можно. Я приходил на каждый проект, которые заходили на поддержку, с откровением в плане: "а чего тут ожидать?"




    Лидером этого анархического движения был и остается Babel. Если вы не помните, к концу 2015-ого вышел Babel 6. И вот эта игра — угадайте кто использует какой набор пресетов. Типа настоящие же хипстеры используют Stage-0, и все что можно: bind expressions, ортогональные классы, и так далее. Угадайка, насколько хипстерским является тот или иной проект, была веселой, но не нравилась. Как показала моя практика, не нравилась эта игра не только мне.




    Все ныли: JavaScript Fatique, мы устали от этого, народ требует перемен. В принципе, перемены пришли.




    2016 год прошёл по знаком демократии. Наконец зарелизился Angular2. У нас уже кто хотел, на том и писал. Сообщество перешло от зоопарка к вменяемым решениям. Появился Create React App — эмберовцы показали Дэну Абрамову, что это круто. Появился Vue2, который я не устаю хайпить. К чему же движется сообщество в 2017-ом году?




    2017-ый год проходит для меня под знаком диктатуры. Диктарура бывает разная. Кому из вас знакома абривиатура BDFL? "Добрый пожизненный диктатор". Первым таким титулом наградили Гвидо Ван Россума. Теперь и Линус Торвальдс рассказывает, что он диктатор, правда добавляет, что не пожизненный. Ну и так далее. О чём идёт речь — что поменяло жизнь, к примеру, реактовского сообщества в 2016-2017-ом году?


    Create React App


    Конечно же это появление Create React App — унифицированный способ быстро стартануть реактовское приложение. Способ, который всем нравится. К примеру, я недавно попробовал Create React Native App — вообще превосходный способ стартануть RN проект с помощью, как говорится, пары комманд и отсутствия головной боли, поскольку я не фанат техники Apple — все эти ужасы с XCode, стараюсь держаться подальше. В чём прелесть? Знаете, у Linux-а, который я очень люблю, как операционную систему, есть хороший девиз: Linux — вы можете всё настроить и вы будете всё настраивать. В случае с Create React App, девиз следующий: вы не можете ничего настраивать, и вам никто не даст это настраивать. Идея в том, что решения приняты за вас. Сообщество приняло какой-то набор "фейсбукизмов". Под капотом Stage-3. Исключительно эти решения, большинство движется в их рамках — когда мы говорим о тирании.


    Prettier


    Есть ещё один проект, к примеру, за который мы регулярно воюем с моим техническим директором — он более ретрограден, чем я, хотя борода у него, как и положено хипстерам, а не у меня. Тем не менее, эту штуку уже приняли многие большие open source проекты. Prettier берет ваш красивый любовно написанный код и форматирует по заранее заданным правилам. Обратите внимание, как и положено хорошему диктатору, плевать он хотел на вашу индивидуальность. Плевать он хотел, что вот в этом сценарии вам удобно держать вот эти две строчки вот так, потому что это красивенько. Что в обмен он предлагает? Унифицированный код. Как мы раньше отличали джуниора от сеньера? В то числе по чистоте оформления кода, который он пишет. Забудьте. Теперь вы пишете код, а я делаю вид, чтобы вы не смогли отличить джуниора от сеньера. Конечно, джуниорам хорошо, когда ты показываешь код, есть шанс получить денег побольше. Но суть в том, что когда только появлялся Prettier, Дэн Абрамов создал в нём превосходное issue: "Пожалуйста, ни в коем случае не добавляйте сюда конфигурацию".




    В Prettier всего пять или шесть настроек, совсем холиварных: использовать точки с запятыми или нет, использовать пробелы или табы, величина отступа, одинарные кавычки или двойные. Почему? Если у вас есть хотя бы 10 настроек, которые вы можете включать-выключать, то это 2 в десятой степени, 1024 возможных комбинаций Prettier, каждую из которых из которых надо тестировать. Это не то, что хочется всем. Всем хочется иметь штуку, которая позволяет коду выглядеть одинаково. Согласен ли я с авторами Prettier-а, как они оформляют код? Не всегда. Готов ли я это терпеть? Я готов. У некоторых моих коллег регулярно боль, что Prettier не согласен с ними. Но опять же, как и положено тирану — кто спрашивает? И это с одной стороны хорошо. Это приятно, когда я могу взять код в любом проекте, я понимаю, что мне не нужно писать огромный style guide, я просто говорю: "слушайте, мы используем Prettier, в прекоммит хуке он это все поправит". Именно так я борюсь со своим техническим директором. Он видит исправленный код в самом конце, когда запушили — всё, поздно уже.


    Власть корпораций


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




    За Angular стоит Google, за React — Facebook, за Vue — ну слушайте, мы все любим эту красивую историю, как Давид побеждает Галиафа, за Vue стоит один человек — Эван Ю, и это на самом деле неправда. Если вы не в курсе, работу Эвана Ю сейчас финансирует более, чем на 60% такая маленькая китайская компания под названием Alibaba. Кто заправляет развитием JS, вы думаете — сообщество? Ну, не совсем. У нас есть страшные злые дядьки под названием TC39 — программный комитет, который решает, что войдет или не войдет в стандарт следующего языка. Давно вы открывали список?




    Google, Google, Google, Microsoft, немного Mozilla, Apple, Intel. Вы правда уверены, что эти люди будут отстаивать ваши интересы? Что-то мне это начинает напоминать предвыборную программу депутата. И самое интересное, до тех пор, пока мои предположения не оправдывались, я относился к этому предположению спокойно, пока меня не задели за живое. tc-39/proposal-cancelable-promises — мы все очень ждем в стандарте языка, который был написан человеком из Google, который шёл-шёл-шёл, дошёл до Stage-1 (или Stage-2, я не помню), и в один прекрасный момент был отозван. Почему? Он сказал: "люди, вот этот proposal встречает очень сильное сопротивление у нас внутри Google, я не хочу больше его вести, и больше со мной об этом никогда не говорите". Я серьёзно, это звучало именно так. В итоге у нас 2017-ый, а fetch мы всё ещё не можем отменить. Это к вопросу о том, куда корпорации всё это двигают.


    Ещё одно. Знаете, никогда не любил CoffeeScript. (Я знаю, что внезапный переход). Однако там была одна замечательная штука. Она называется Элвис-оператор. Когда вам нужно лезть во вложенный объект, вы могли вместо точки поставить знак вопрос и точка, и сказать что если вот эта штука null или undefined, то вернуть undefined. Некоторое время назад, в React Native блоге появился рассказ, что мы презентуем вам idx — это функция, которая делает абсолютно тоже самое, что и Элвис-оператор.




    И это не какой-то магический геттер — потом это всё дружно транспайлится Babel-плагином для idx, и превращается в цепочку if-ов. Пока ничего интересного. Такое можно наэмулировать и на Proxy, например, придумать много разных вариантов. Что мне стало интересно? Поскольку я большой поклонник статической типизации, а они сказали, что вот эта штука полностью совместима с Flow (статическим типизатором от Facebook), мне стало интересно, как же они это обеспечили — это же достаточно сложная задача обеспечить корректный вывод статических типов. Полез в исходники Flow.




    Тип функции idx — $Facebookism$Idx. Вот всё, что вам нужно знать, как корпорации тихо и незаметно проникают в нашу жизнь. Отметьте, что таких "фейсбукизмов" объявлено больше одного. Корпорация, в данном случае — Facebook, развивает нужные инструменты (не то, чтобы исключительно), с той точки зрения, с которой полезно им. Это бизнес. OpenSource стоит на самом деле очень дорого. Очень много людей вкладывает в это свои деньги, многие жертвуют своим временем. И корпорации развивают это туда, куда нам надо. Нам всего лишь остаётся покориться.


    OCaml


    Какую ещё одну интересную тенденцию я заметил в 2017-ом. Дальше мы начинаем очень опциональную зону. Краткая версия — учите OCaml.




    Не заходит. Ладно, пойдём длинным путём.


    Static typing


    Все мы любим статическую типизацию. Нет — да? Хорошо. Я не устаю цитировать восхитительную фразу, что люди JS-сообществе делятся на два типа: те, которые понимают, что нам иногда нужна статическая типизация, и те, кому ещё нет 22-ух. Конечно утрирую. Но никто не будет скрывать, что последнее время движение вокруг статической типизации набирает силу. Причём удивительно, когда появился Dart? С мощной статической типизацией. И кому он был нужен? Я не спрашиваю, где теперь Dart. Такое можно спросить о половине проектов Google. Хотя недавно вышла третья версия Angular-Dart, достаточно удобный бридж между Angular2 и Dart.




    Так вот, у нас есть TypeScript. Который я регулярно ругаю. Но, справедливости ради, он очень сильно развивается, с каждой версией улучшает свой вывод типов. Хотя в некоторых местах всё ещё бесполезен чуть более, чем полностью. Не то, чтобы мне платит Facebook. Но Flow мне нравится больше, чем TypeScript. Хотя вот прямо сейчас я пишу на четвёртом Angular-е и плачу.


    ReasonML




    Немножко инсайда, недавно внутри Facebook было собрание людей, которые пилят Flow на OCaml-е, и они сказали, что как-то плохо, что Flow ощущается на задворках экосистемы, потому-что Flow — это важная часть React Native. (Настолько важная, что они сломали определение Flow для RN и месяц этого никто не замечал — к вопросу о "важно"). Почему это важно? А мы хотим оптимизировать код, который мы генерируем под мобильные платформы на основании тех статических типов, которые писать будут в коде. У Angular в NativeScript тоже такие задумки идут. И что же делать? Один из крутых апологетов Flow, Патрик Стафер, разместил интересный твит: "В ближайшем будущем, если вы покажете мне ещё одну ошибку, я вас спрошу, почему вы ещё не пишете на ReasonML?"




    ReasonML — это очередная попытка Facebook переизобрести OCaml. Почему Facebook делает ставку на OCaml? Ну, он им понравился. Сначала был Reason — пишете код на OCaml, а на выходе получаете код на JS. Но недавно выпустили очень-очень странную вещь — компилятор из JS в OCaml. Существует предположение, что Facebook задумывается о переводе всего своего фронтенд стека на OCaml. Для этого они собираются взять существующие JS-имплементации, перевести их на OCaml, а потом посадить миллиард интернов вылизать это на Reason-е. И после этого вы получаете красивый клиентский код, генерирующийся из OCaml, очень быстрый сервер-сайд. К примеру, Facebook-овский Flow написан на OCaml и парсер, который строит AST (абстрактное синтаксичекское дерево) из текста кода JS, в три раза быстрее, чем тот же парсер, использующийся Babel-ем. При прочих равных, и при том, что этот парсер является одним из таргетов для оптимизации V8. Т.е. команда V8 из Google следит, чтобы в этом парсере всё работало быстро.


    MirageOS



    Ещё одна штука, на которую делает ставку Facebook, которая из всего этого мне нравится (я отношусь подозрительно к OCaml), это MirageOS. Что это такое? Все любят Docker. Если вы ещё его не любите, то вам нужно срочно полюбить. Для деплоймента и прочее. Стандартизированный контейнер — это круто, проблема в том, что оно весит под 100 мегабайт. Много! MirageOS — это штука для сборки unikernel. Т.е. такая штука, которая берет ваше приложение, в идеале приложение, которое имеет минимум рантайм-зависимостей (люди, разрабатывающие на Go и на OCaml, радостно машут флажками — там один бинарник на выходе без зависимостей); и склеивает ваше приложение с ядром. Берет только необходимое, в итоге вы можете получить контейнер весом 5 мегабайт. Круто. Facebook наверно хочет сэкономить место на своих серверах. Это всё очень быстро стартует, очень быстро деплоится, и мне хочется верить, что они наберут сообщество. Пока про MirageOS никто не знает.


    Ещё было про (видео с нужного места): Lighthouse и PWA, WebAssembly, WebVR.

    Поделиться публикацией
    Похожие публикации
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 239
    • +2

      Про отсутствие конфигурации в Create React App — есть обходные пути: react-app-rewired, custom-react-scripts. И для TypeScript существует форк. Кстати, "важные новости": Microsoft выложил TypeScript-React-Starter на базе Create React App.


      Prettier vs Standard — в чём разница? Standard ужесточает холиварные вопросы, которые можно конфигурировать в Prettier. Недавно прикрутил Standard и безумно счастлив. Есть несколько плагинов для редакторов кода, которые позволяют использовать Prettier и Standard вместе — оно надо? Пока не разобрался, какая будет польза от совместного использования.


      В мире Clojure есть ещё один прекрасный инструмент — Parinfer. Привет табуляции Python и CoffeeScript. Не знаю почему общепринято хейтить CoffeeScript, он меня очаровал этой фишкой настолько, что весь остальной код веб-проектов перевёл на синтаксис с табуляцией: JADE для HTML-шаблонов, Stylus для CSS, YAML для JSON. Увы, всё это в прошлом.

      • 0

        Отвечаю сам себе — беда. :)


        Выпилил Standard. Prettier более лоялен. Например, мне нравится оставлять запятые в конце объектов и массивов:


        {
          a,
          b,
          c, // запятая позволяет добавлять следующее поле объекта без редактирования предыдущего
        }

        Ещё довод, CRA рекомендует Prettier.


        Но Prettier-ESLint забраковал, он гробит комментарии. Подключил автофикс в хуке на прекоммит, можно пощупать пример.


        Что надо для счастья — фрагмент из package.json


        {
          "devDependencies": {
            "husky": "^0.13.3",
            "lint-staged": "^3.4.1",
            "prettier": "^1.3.1",
          },
          "scripts": {
            "precommit": "lint-staged"
          },
          "lint-staged": {
            "*.js": [
              "prettier --print-width 100 --single-quote --trailing-comma all --no-semi --write",
              "git add"
            ]
          }
        }
        • 0

          Хм интересный способ, мне как-то всегда хватало того, что делает WS перед комитом, или когда я его об этом попрошу, но он далеко не всегда делает то, чего я хочу, например в том же JSX...

      • +4
        Автор пароноик, что плохого в том, что за определенной технологией стоит целая компания? Разве не в ее интересах продвигать свою технолгию, улучшать ее? Это не похожа на ситуацию с IE6, когда Microsoft тормозила веб.

        Чаще всего, проекты, за которыми никого нет, они просто вымирают (PhantomJS к примеру), когда заканчивается хайп или разработка становится очень сложной, а уделять слишком много времени Open Source голодный жилудок не дает.
        • +2

          Ну вообще оно так, но не так)
          У наличия финансирования опенсорс проекта есть и плюсы и минусы.
          Плюсы:


          • Разработчикам хватает на покушать
          • Есть реклама проекта

          Минусы:


          • В текущее время ситуация такая: один проект поддерживает одна компания, и тут, соответственно, появляется суровое влияние этой компании. То есть появляется диктатура, а это на опенсорсе ооочень плохо сказывается.
          • Если финансирование компанией заканчивается, то проект задыхается в разы быстрее, чем проект, который вообще не имел финансирования. Потому что проекту самому приходится культивировать всё то, что за него делала компания, а если точнее, то люди из компании, специально обученные для этого.
          • +2
            Речь идёт о богатых компаниях, типа google, facebook. К примеру, вот взяли они разработчика redux к себе и теперь он то и дело занимается им, а так же самим react'ом и все вроде бы хорошо.
            Мне кажется диктатура не может быть такой — «А давай те нагадим всем, и сделаем react медленным!!!1»
            Они в первую очередь переживают за проект, хотят дать ему больше возможностей и предлагают то что полезно проекту, это финансирование, а в ответ получают рекламу бренда, немножечко хайпа среди разрабочиков и крутой инструмент, который им самим интересен, ведь они финансируют то что им самим в первую очередь нужно!?

            Мне кажется или я слишком наивный? Поправьте меня пожалуйста
            • 0

              Тут просто реклама идёт двусторонняя. Сами подумайте. Нанять разраба, у которого несколько k звёзд на гитхабе — это реклама обоим. А если этот человек с несколькими k звёзд делает крутую технологию, то тут уже будет вообще рекламища похлеще всякой 8 900 55… Потому что разраб "работает на крутых людей, которые не дадут спуску", а компания "финансирует такой крутой проект, который вообще-то опенсорсовский".

            • 0
              а это на опенсорсе ооочень плохо сказывается.

              Приведите пример успешного open-source продукта где нет диктатуры или жесткой политики внесения изменений?

              • 0

                curl, wc…
                Давайте сначала определимся что значит "успеный продукт" и "жёсткая политика внесения изменений".

            • +2
              Автор пароноик, что плохого в том, что за определенной технологией стоит целая компания?

              В современном программировании существует довольно жесткая конкуренция между технологиями. Поддержка корпорацией своей внутренней разработки может создать видимость того, что эта технология хорошая и вообще кому-то нужна. Из сразу вспомнившегося — GWT. Из современных примеров по-видимому второй Ангуляр.
              • 0
                Будут внедрять нужные компании фитчи, в конкретные компании, а не универсальные механизмы для сообщества. Но это не обязательно.
              • 0
                Когда-то верилось с трудом, ведь слова что в ru сегменте вся информация устаревшая, казались неправдой, такого просто не могло быть, ведь я и так успевал с трудом. А теперь я реально знаю что скоро, когда angular будет уже в прошлом, у нас скажут что пришла пора учить angular! Два года назад заминусовали бы за упоминание react рядом с typescript, который тогда считали чем-то ужасным. Печалит лишь тот факт, что когда начнут говорить о том что из реакта ну не как нельзя собрать полноценный angular, второй уже тоже будет на полках истории. Попробуйте angular и Вы поймете что всю свою жизнь мечтали именно о нем.
                • 0
                  Прямо сейчас в работе несколько месяцев проект на angular 2-4 после 2х лет реакта. Сказать, что впечатление негативное — не сказать ничего.
                  • 0
                    А у меня много примеров, когда выходило наоборот — от реакта плевались. Мне кажется, каждый инструмент хорош по-своему и не надо тратить время на бесконечные холивары.
                    • +2
                      Вспомните свои слова ещё через два года.
                      • –2
                        И холиваров быть не может, angular максимально на сегодняшний день реализует компонентный подход в декларативном стиле. Просто нужно ещё много лет чтобы люди это поняли, приняли, подождали ещё чуть-чуть и только потом, когда как им покажется все утихлось, они начнут говорить что, да, вот angular действительно хорош. Два года назад реактовцов считали ненормальной прослойкой и пророчили успехи ember и meteor, а ts называли очередным coffee. Сегодня все кардинально поменялось и как человек наблюдающий за этим много лет могу сказать что существует завтра будет так как скажут об этом те, кто зарабатывает на уроках деньги. А делают они это специально медленно выжимая все соки и тем самым останавливая развитие ru сегмента. И это нормально, у каждого своя дорога. Лично я с первых дней люблю и реакт и ts точно так же как полюбил angular, в то время как от первого отказался сразу же из-за его несуразной идеологии угодить всем и сразу.
                        • +8
                          максимально на сегодняшний день реализует компонентный подход в декларативном стиле
                          Компоненты там — смех один. Ни HoC не сделать, ни отнаследоваться нормально, ни расширить другой, так как нет ни рендеринга в качестве хоста, ни возможности пробросить пропсы.
                          Декларативный стиль — это когда для рендеринга попапа надо руками вставить разметку в body? Или когда ngComponentOutlet выбрасывает событие в котором нужно руками проставить аутлету все inputs/outputs? Или то же самое, связанное с ContentChildren, ViewChild, TemplateRef? Ну смешно просто.

                          Инкапсуляция стилей — смех один. Привязка класснеймов к аттрибуту не изолирует компонент от возможного влияния снаружи через этот класснейм.
                          Из-за того, что компонент не импортирует другой при рендеринге, а берет из модуля, ломается граф зависимостей и, как следствие, порядок стилей в выходном css.

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

                          PS. Я это все не холивара ради, а чтобы указать на реальные существующие проблемы.
                          • 0
                            не понял насчет разметки в body для попапа. Кто Вам запрещает написать директиву на которая этот темплейт вставит в ?
                            • +2
                              Не обращайте внимания, людям которые начали учить программирование с математики очень сложно понять что отображение, это геометрия, а связи, это символика и лишь алгоритмы, это алгебра. Человек который много лет учится и достигает результатов решать первое и второе с помощью третьего может никогда не понять что есть другие более удачные подходы. Программисты ооп понимают это и там где нужно писать в функциональном стиле, делают это, а там где не нужно, они пишут на чем-то другом. И что странно, ооп программисты понимают все парадигмы, а функциональщике не могут.
                              • 0
                                Вы в своих рассуждениях как-то так легко и невзначай упускаете такой момент, что не все бросаются в крайности, и у этих «функциональщиков, которые не могут» может быть приличный ооп-бэкграунд.

                                Я вам не про парадигмы писал, и вообще не хочу уходить в эти холивары. Я лишь опровергаю ваше крайне необоснованное утверждение о компонентах и декларативности там, где ничего этого нет.
                                • 0
                                  Дело в том что много-много лет назад я велся на такие вот предположения, но потом спустя много лет видел, как те кто это предположения предполагал, доказывали своими поступками что они не относятся к тем, о ком говорили. И такое видел много раз и как правило это были люди, которые занимались, как не странно, образованием. Каждое поколение программистом повторяется одна и та же картина и я уже не помню на какой итерации решил остановится считать, ведь понял, что они говорят не со зла и не о себе или ком-то, а об абстрактных представлениях.
                                  Лично Вы назвали проблемы, которые я даже не понимаю как можно создать! То есть у Вас мышление работает как-то совсем по другому. И это не плохо, возможно даже Вы бы смогли быть крутым писателем компиляторов или драйверов, то есть в тех областях где нужна математика. Но я против когда в архитектуру тащат алгебру. Это вот как представьте что к Вам придет слесарь-диетолог и скажет что у Вас пора в раковке от пробки встала, а возможно сосед от переизбытка калорий начал изливаться салом находясь в омывальне и его секреции бляшками пристыли к водовой системе. И ещё бы он пожаловался что ему трудно работать зная что существует шунтирование. Кто бы он был по Вашему, глупец или хвастун?
                                  • +1
                                    Каждое поколение программистом повторяется одна и та же картина и я уже не помню на какой итерации решил остановится считать
                                    Поведуете несведающим об опыте печальном?

                                    Лично Вы назвали проблемы, которые я даже не понимаю как можно создать! То есть у Вас мышление работает как-то совсем по другому.
                                    Вы не понимаете, что такое HoC, и для чего они делаются? Или не понимаете, зачем нужна инкапсуляция стилей? Не понимаете как порядок импортов поверх вебпака влияет на порядок стилей в css?

                                    Но я против когда в архитектуру тащат алгебру.
                                    Простите, но о чем вы вообще? Какая алгебра?

                                    Ну а уж пример ваш… браво
                                    • 0
                                      Конечно, несколько лет пишу не пойми что и не понимаю не о стилях не о чем-то другом.
                                      Но зато, у меня нет Ваших проблем. А алгебра, это та которой Вам в унылом es6 не хватает о чем Вы ниже вчера поведали.
                                      • 0
                                        ну то есть когда у нас данные в куче с операторами над ними определенными (ООП, классы и объекты) — то это кавайно и кошерно, а когда типы ДАННЫХ содержат только данные а операторы вынесены в алгебру — то это не по феншую? Ну ок.
                                        • 0
                                          О как вы здорово с «алгебры в архитектуре» на «алгебру в es6» перескакиваете!
                                          Смотрите, если у вас этих проблем нет, я за вас только рад, пусть их и дальше не будет. А я уж буду с горем пополам набираться опыта и, надеюсь, меня не постигнет участь этих несчастных:
                                          те кто это предположения предполагал, доказывали своими поступками что они не относятся к тем, о ком говорили. И такое видел много раз и как правило это были люди, которые занимались, как не странно, образованием. Каждое поколение программистом повторяется одна и та же картина и я уже не помню на какой итерации решил остановится считать, ведь понял, что они говорят не со зла и не о себе или ком-то, а об абстрактных представлениях
                                          • 0
                                            Ну я уверен что архитектура приложений Вы строите как «тут лямбда, тут функтор, а тут будет пару монад и тысячу оберток и все смешаем в общую кучу и пусть доступ будет везде и ещё раз тысячу оберток».
                                            • 0
                                              Вы совершенно не имеете представления о том, что такое «лямбды, функторы и монады», раз думаете, что эти вещи относятся к архитектуре. Я бы рекомендовал вам ознакомиться с хорошей книжкой, причем на примере языка для клиент-сайда.
                                            • +1
                                              хватит говорит о калбэкаде, давайте поговорим о аде из оберток и о конструкциях типа — а я делаю вот так —
                                              var friend = (((props ||{}).user ||{}).friends[0] ||{}).friend;
                                              

                                              ну ты вообще лох, нужно вот так —
                                              var friend = null;
                                              props && props.user && props.user.friends && props.user.friends[0] && /* !!! */ friend = props.user.friends[0].friend;
                                              

                                              Только начинали радоваться что jQ уходит в прошлое, на тебе промисы плохо, es6 просто унынье и давайте все омрачим идрисом.
                                              • 0
                                                У вас что, от идриса так, эммм, «наболело»? Или я как-то оскорбил ваши es6-чувства? Мы ж вроде в этой ветке вообще по другому поводу?
                                                • 0

                                                  Вы так хорошо меня "процитировали". Может представите свой способ решения таковой задачи без "ада"? Может тоже свой велосипед накатали? Или всё же пользуетесь элвис-оператором?

                                                  • 0

                                                    Мне такой "велосипед" нравится — https://lodash.com/docs/4.17.4#get


                                                    var object = { 'a': [{ 'b': { 'c': 3 } }] };
                                                    
                                                    _.get(object, 'a[0].b.c');
                                                    // => 3
                                                    
                                                    _.get(object, ['a', '0', 'b', 'c']);
                                                    // => 3
                                                    
                                                    _.get(object, 'a.b.c', 'default');
                                                    // => 'default'
                                                    • 0
                                                      Мне такой "велосипед" нравится

                                                      Вам сюда :)

                                                      • 0

                                                        Оригинальности 0… Это слишком не интересный велосипед, которым пользуются все, если в проекте лодаш есть. В андерскор тоже вроде есть _.get, но я андерскором не пользуюсь.

                                                        • 0

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

                                                          • 0

                                                            Да я тоже писал аналог, только я писал немного по-другому, у меня разделители были другие, было что-то типа такого:


                                                            gIfIs(object, 'a#0.b.c', 0);

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


                                                            Надо будет переписать кое-что...

                                                            • 0

                                                              Меня в данный момент напрягает, что _.get получает все свойства, даже если они не собственные. Логичней было бы разделить на _.get и _.getIn (по аналогии с _.has и _.hasIn).


                                                              _.has([], 'forEach')
                                                              > false
                                                              
                                                              _.hasIn([], 'forEach')
                                                              > true
                                                              
                                                              _.get([], 'forEach')
                                                              > function forEach() { [native code] }
                                      • +1
                                        Никто не запрещает, более того, они уже есть — ngComponentOutlet и ngTemplateOutlet. Но ни одна из этих директив не поддерживает контекст (автоматическую, а главное декларативную, простановку нужных свойств), и, чтобы достичь нужного результата, нужно возвращаться к императивщине и распихивать руками нужные значения в нужные inputs.

                                        Посыл был не в том, что это не работает, а в том, что это не декларативно.
                                        • 0
                                          Я знаю точно, что у меня нет проблем с реактом и у меня нет проблем с angular. Как Вы проектируете и о чем говорите я тоже не понимаю. Я желаю людям развиваться, а Вы не использовать angualr.
                                          • 0
                                            Да согласен, иногда приходится писать больше чем хотелось бы… По моему только в реакт можно писать что-то типа:
                                            return <Component {...this.props} />
                                            


                                            Я так понимаю основная проблема в этом? В реализации декоратора. Правильно?
                                            • 0
                                              Именно! Одна проблема — отсутствие механизма задания inputs/outputs скопом (spread), вторая — что у меня всегда будет ненужная обертка вокруг <Component/>
                                    • +1
                                      Сказать, что впечатление негативное — не сказать ничего.

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

                                      • 0
                                        пропсы в хоки не прокинишь и попапы нужно самому руками в боди вставлять! Это же после стольких лет сделать такую жесть даже гуглу не подсилу. Просто представьте что по мнению автора там за чудовище из каменного века получилось :) Но лучше перестать спорить, а то только представить что в angular будут советовать отказываться от сервисов в пользу свалить все в одну кучу.
                                        • +1
                                          пропсы в хоки не прокинишь

                                          делаем отдельный компонент, экспоузим сервис который уже можно инджектить куда надо и вроде как не вижу фундаметальных различий.


                                          Ну то есть, вы и так и так должны в своем компоненте получить возможность как-то "вставить попап в боди". Разница минимальна.

                                          • 0
                                            Подход, который предлагается официально — либо вставить TemplateRef (надо сначала найти в своей разметке) во ViewContainerRef, либо класс компонента через ComponentFactoryResolver в такой же ViewContainerRef. Чуть более декларативное решение предлагается через ngComponentOutlet и ngTemplateOutlet.

                                            Да, это все доступно, и да, проблема решаема. Но большим отличием является то, что мне в любом случае нужно прибегать к императивным вызовам для простановки пропсов в создаваемые динамически компоненты. «Вставить попап в боди» — это утрирование, вы же понимаете, что проблема глубже.
                                        • +1
                                          Фундаментально меня не устраивает попытка команды ангуляра усидеть на двух стульях — то есть «мы как бы все из себя такие ооп» (я ничего не имею против ооп), но еще и за реактом хотим успеть, мы хотим компоненты, декларативный ui и вот это все. Если бы они не гнались за композицией в интерфейсе, то все бы было хорошо. Наверное, это отвечает на оба вопроса — и похоже и совсем по-другому.
                                          Я чувствую, что меня насильно пытаются втянуть в бесполезное набрасывание на вентилятор. Это тема как минимум уже изъзжена вдоль и поперек и ничего нового я вам не расскажу.
                                          • –1
                                            За реактом? Хотя бы сказали за c#, java, а то реакт, это как-то мелко слишком. Вспомните себя через пару лет когда пойдут статьи «ангулар это как реакт только круче», «как я полюбил ангулар» и поругайте себя за то что два дня пишите.
                                            • 0
                                              Ох, правда, шарп с джавой? «ангулар это как реакт только круче»? Вы вообще понимаете, о чем пишете? :)
                                            • +2

                                              Окей… хорошо.


                                              мы хотим компоненты, декларативный ui и вот это все.

                                              Представьте на секундочку что компоненты это объекты. И бац, мы можем делать композицию объектов! И бац, объектно-ориентированный код вполне может быть декларативным! И это не говоря уже о том что идея UI как композиция компонентов настолько не нова… Подобные подходы использовались практически во всех UI фреймворках на десктопах.


                                              усидеть на двух стульях

                                              вы про объекты vs функции? опять же, что если я скажу что между OO и FP принципиальной разницы… нет. Ну то есть если убрать эти аксиомы в духе "все есть объект" и "все есть функции" и сделать "есть объекты и функции" то в целом это ложится на обе парадигмы просто прекрасно. А далее уже нюансы языков программирования и системы типов.


                                              Наверное, это отвечает на оба вопроса — и похоже и совсем по-другому.

                                              Я вижу разницу лишь в том где происходит дерти чекинг. У ангуляра между стэйтом и вьюхой, а реакта между вьюхой и реальным DOM. Соответственно профит между тем и другим виден исходя из того чего у нас больше — стэйта или мутации DOM.


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


                                              Это тема как минимум уже изъзжена вдоль и поперек и ничего нового я вам не расскажу.

                                              Согласен, но я все же считаю что все это настолько похоже друг на друга...

                                              • 0
                                                Представьте на секундочку что компоненты это объекты. И бац, мы можем делать композицию объектов! И бац, объектно-ориентированный код вполне может быть декларативным!
                                                Это все здорово! И именно под этим соусом подается в офф-доках. Но, представьте, что есть у вас одна кнопка с каким-то интерфейсом взаимодействия и со шрифтом в 16px. И вам надо из нее сделать точно такую же кнопку но со шрифтом в 14px. Как это сделать без копипасты интерфейса? Создать класснейм, сложить его в глобал и вставлять везде? Ну так себе. Директива тоже не спасет, так как в нее нельзя заинкапсулировать стили. Отнаследоваться от кнопки (вообще это первое, что приходит в голову в ооп-движке)? Но нет, метаданные декоратора не наследуются, так что вам придется вручную скопипастить всю конфигурацию декоратора.

                                                OO и FP принципиальной разницы
                                                Разница в том, что в случае с ООП, сцена дается как данное окружение, и в этой сцене я рисую кнопку, задаю ей параметры, тут рисую инпут, задаю параметры. ФП — сцена, это такая сцена, в которой есть кнопка с определенными свойствами на определенном месте вместе с инпутом с определенными свойствами в определенном месте. Вот она декларативность, чувствуете разницу? Собственно, это и относится к разнице. И тот и тот подход годится, но только по отдельности, а не в каше.
                                                • +1
                                                  Как это сделать без копипасты интерфейса?

                                                  Для начала зададимся вопросом. Вот этот модифицированный элемент UI — маленькая кнопка, это внешний мир знает или сама кнопка? Ну мол мы должны из контекста менять стили или мы лишь задаем контекст кнопке а она уже сама знает как себя рендрить?


                                                  Пишем в стилях кнопки:


                                                  :host-context(.btn-small) {
                                                      font-size: 14px;
                                                  }

                                                  и используем наш компонент:


                                                  <my-btn (click)="doAction()" class="btn-small">My Button</my-btn>

                                                  тем самым мы повышаем реюз компонента. При этом не сильно нарушая open-close принцип.


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

                                                  Вообще-то вы сейчас обрисовали то как это должно быть в объектом мире. Просто куча акторов которые могут обмениваться сообщениями. Но координаты эктора это его личное дело а не сцены.

                                                  • 0
                                                    Это внешний мир знает, базовая кнопка не должна знать, что она где-то может использоваться с каким-то флагом, причем менять свое поведение, подстраиваясь под этот флаг. Если расширение не ограничивается лишь размером шрифта, а например включает изменение поведения, это тоже все упаковывать в базовую кнопку?
                                                    Ваш пример почти похож на правду, если бы можно было сложить это дело в отдельный компонент my-small-btn, а класс btn-small лежал бы в модуле my-small-btn. Но так не сделать, так как вокруг my-btn будет обертка my-small-btn.

                                                    Просто куча акторов которые могут обмениваться сообщениями.
                                                    Различие в том, как вы их создаете.
                                                    //OOP
                                                    const scene = new Scene();
                                                    const button = new Button();
                                                    button.content = 'hi'; //imperative
                                                    scene.add(button); //imperative
                                                    const input = new Input();
                                                    input.value = '123'; //imperative
                                                    scene.add(input); //imperative
                                                    

                                                    //FP
                                                    const scene = Scene([ //declarative
                                                      Button({ //declarative
                                                        content: 'hi'
                                                      }),
                                                      Input({ //declarative
                                                        value: '123'
                                                      })
                                                    ]);
                                                    


                                                    Можно достичь такой же декларативности и в ооп, и она, собственно, и достигается в ангуляре. Только вот она превращается в тыкву, когда вам нужно, например, кнопку создать в сторонке так же декларативно в текущем контексте, а потом так же декларативно отрендерить. И тут начинается всякое непотребство из серии ComponentFactoryResolver и компании.
                                                    • +1
                                                      Различие в том, как вы их создаете.

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


                                                      Так что по сути мы будем иметь что-то типа:


                                                      const render = compose(
                                                           Button,
                                                           Input    
                                                      );
                                                      
                                                      scene(state); // вычисляет весь DOM для сцены

                                                      А теперь вспоминаем что в jS функции это таки объекты. И что мы на самом деле сделали — это композицию имутабельных объектов, по сути не имеющих своего стэйта. Их задача — взять стэйт и продьюснуть DOM.


                                                      А то что вы сделали мутабельные объекты да еще и инкапсуляцию сломали к чертям… ну это ваш осознанный выбор и он не имеет ничего общего с классическим ОО подходом. Это больше похоже на C++ way, который больше про структурное программирование нежели actor model.

                                                      • +1
                                                        Ради бога, через compose, через children — одни и те же яйца.

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

                                                        Ну являются функции объектами в js, ну свели вы их в композицию — прекрасно. Я вам не о невозможности этого пытаюсь донести, а о подходе к «донастройке» функций (окей, объектов, компонентов, как угодно) уже находящихся в композиции в angular 2. Делается это достаточно костыльно и недекларативно, с чего все это обсуждение вообще началось.
                                                        Я крайне не хочу вдаваться в дебри различий ооп и фп, изначальный посыл был совсем другой.
                                                      • +1
                                                        Вы штаны через голову надеваете. ComponentFactoryResolver — низкоуровневое апи, что-то вроде рефлексии, для этих вещей оно не предназначено. Для аналога HOC (а это анти-паттерн, само по себе, и в Реакте используется только из-за бедности) есть ng-content (бывший трансклюд), доступ к текущему контексту у него есть по дефолту, а внутренний скоп компоненты инжектится через template reference variable. Это в том случае, если требуются «полноценные» HOC, для простого подмешивания поведения используются директивы или наследование (в зависимости от того, что и как надо подмешать).
                                                        • 0
                                                          ComponentFactoryResolver — низкоуровневое апи, что-то вроде рефлексии, для этих вещей оно не предназначено.
                                                          Да что вы говорите

                                                          а это анти-паттерн, само по себе, и в Реакте используется только из-за бедности
                                                          Да что вы говорите

                                                          есть ng-content
                                                          И каким же образом вас ng-content спасет от лишней обертки? Даже если у вас весь темплейт это <ng-content><ng-content/>?

                                                          а внутренний скоп компоненты инжектится через template reference variable
                                                          Ну так я и пишу, нужно руками распихать все input/outputs в этот референс. Где тут декларативность?

                                                          для простого подмешивания поведения используются директивы или наследование (в зависимости от того, что и как надо подмешать).
                                                          Через директиву вы не подмешаете стили. Через наследование вы не наследуете конфигурацию декоратора — придется копипастить.
                                                          • 0
                                                            > Да что вы говорите

                                                            Именно то, что написано по указанной ссылке. Вы же ее прочли?

                                                            > Да что вы говорите

                                                            Не надо путать HOF и HOC. С точки зрения домена компонент не является ф-ей (у него, как минимум, есть еще внутреннее состояние и метаданные). При этом HOC — как раз обычная функция. Название «Higher-order component» удобно, но по факту не является корректным.

                                                            > И каким же образом вас ng-content спасет от лишней обертки? Даже если у вас весь темплейт это <ng-content><ng-content/>?

                                                            От какой обертки?

                                                            > Ну так я и пишу, нужно руками распихать все input/outputs в этот референс. Где тут декларативность?

                                                            Здесь есть несколько моментов:
                                                            1. Упомянутые выше HOF вы как вызываете? Точно так же распихивая аргументы руками, менее декларативными они от этого не становятся, правда?
                                                            2. За показанный выше проброс аргументов через spread надо вырывать руки.
                                                            3. Он возможен только в том случае, когда у вас аргументы чисто случайно совпадают — то есть, практически никогда.

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

                                                            Потому что стили — это не поведение, все верно.

                                                            > Через наследование вы не наследуете конфигурацию декоратора — придется копипастить.

                                                            Во-первых, конфигурация компонента — это три строчки, так что если бы копипаста и была, то это не помешало бы совершенно никак. Но ведь ее на самом деле и нет, вот в чем штука. Что именно вы копипастите? Стиль? Так вы его переопределили. Селектор? Он тоже другой. Только темплейт остается, да и тот не всегда.
                                                            • 0
                                                              Именно то, что написано по указанной ссылке. Вы же ее прочли?
                                                              Ну тогда ткните меня носом в место, где написано, что это low-level и что не используется для динамического создания компонентов.

                                                              Не надо путать HOF и HOC. С точки зрения домена компонент не является ф-ей (у него, как минимум, есть еще внутреннее состояние и метаданные).
                                                              Это вот, простите, почему? У компонента прекрасно может и не быть состояния. И чем тогда он будет являться? Ничем, кроме как функцией от inputs.

                                                              От какой обертки?
                                                              @Component({
                                                              	selector: 'my-foo',
                                                              	template: '<ng-content></ng-content>'
                                                              })
                                                              class Foo {
                                                              }
                                                              
                                                              @Component({
                                                              	selector: 'enhanced-foo',
                                                              	template: '<my-foo>enhanced</my-foo>'
                                                              })
                                                              class EnhancedFoo {
                                                              }
                                                              
                                                              //markup
                                                              //<enhanced-foo><my-foo>enhanced</my-foo></enhanced-foo>
                                                              


                                                              Точно так же распихивая аргументы руками, менее декларативными они от этого не становятся, правда?
                                                              Вы что, правда не видите разницы?
                                                              @Component({
                                                              	selector: 'my-foo',
                                                              	template: '<ng-container #container></ng-container>'
                                                              })
                                                              class Foo implements AfterViewInit {
                                                              	@ViewChild('container', {
                                                              		read: ViewContainerRef
                                                              	})
                                                              	containerRef: ViewContainerRef;
                                                              
                                                              	@Input()
                                                              	ComponentClass: Type<{
                                                              		someField: any
                                                              	}>;
                                                              
                                                              	constructor(private componentFactoryResolver: ComponentFactoryResolver) {
                                                              	}
                                                              
                                                              	ngAfterViewInit() {
                                                              		const factory = this.componentFactoryResolver.resolveComponentFactory(this.ComponentClass);
                                                              		const componentRef = this.containerRef.createComponent(factory);
                                                              		const {instance} = componentRef;
                                                              		instance.someField = '123'; //Это что, декларативно?
                                                              	}
                                                              }
                                                              
                                                              //или
                                                              const MyFoo = ({ComponentClass}) => (
                                                              	<div>
                                                              		<ComponentClass someField={123}/>
                                                              	</div>	
                                                              );
                                                              


                                                              За показанный выше проброс аргументов через spread надо вырывать руки
                                                              Это ваше личное мнение, и как аргумент я бы вас попросил его не приводить.

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

                                                              Во-первых, конфигурация компонента — это три строчки, так что если бы копипаста и была, то это не помешало бы совершенно никак
                                                              Простите, но на аргумент как-то тоже не тянет. Что за поблажка, раз 3 строчки — значит можно копипастить? А то, что компонент должен быть blackbox'ом вас не смущает? Стили я, может, хочу добавить, расширить базовые. Темплейт я, может, тоже как-то хочу переиспользовать. И вы предлагаете прописывать в расширяющем компоненте пути до частей реализации базового компонента? Ну что-то с трудом тянет на решение.

                                                              • 0
                                                                > Ну тогда ткните меня носом в место, где написано, что это low-level и что не используется для динамического создания компонентов.

                                                                Для динамического создания компонентов и используется. HOC тут при чем? Слово «Dynamic» я там вижу, слов «Higher-order» — нет. Это вам не говорит ни о чем?

                                                                > У компонента прекрасно может и не быть состояния.

                                                                Может и не быть, но в общем случае — оно есть.

                                                                > Вы что, правда не видите разницы?

                                                                Ну так вы продолжаете штаны через голову натягивать.

                                                                @Component({
                                                                    selector: "foo",
                                                                    template: `<div><ng-content></ng-content></div>`,
                                                                })
                                                                export class FooComponent {
                                                                    public data = 123;
                                                                }
                                                                
                                                                // <foo #scope><my-component [someField]="scope.data"></foo>
                                                                


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

                                                                А всякого роды ref'ы с фабриками — это либо инструмент для построения сложных УИ по динамических конфигурациям, либо АПИ для structural directives.

                                                                > Простите, но на аргумент как-то тоже не тянет. Что за поблажка, раз 3 строчки — значит можно копипастить?

                                                                Совсем несложно написать свой вытягивающий метаданные из суперкласса декоратор (это же обычная функция), если вам это прямо надо. Будете вместо Component(...) писать @DerivedFrom(BaseComponent, {… если надо что-то перегрузить..}). То есть это решаемая проблема, и решаемая без каких-то особых затрат.
                                                                • 0
                                                                  Для динамического создания компонентов и используется. HOC тут при чем? Слово «Dynamic» я там вижу, слов «Higher-order» — нет. Это вам не говорит ни о чем?
                                                                  А где вы увидели, что я говорю, что оно используется для создания HOC?

                                                                  Может и не быть, но в общем случае — оно есть.
                                                                  И что, он теперь не функция? Более того, компонент со стейтом (даже класс, представьте) — это тоже функция от инпутов, но с сайд-эффектом в виде стейта.

                                                                  Ну так вы продолжаете штаны через голову натягивать.
                                                                  Ну а вы продолжаете чушь нести. Окей, я упрощу вам задачу. Вот есть кнопка my-button. Сделайте такую же кнопку my-button-with-icon, но с доп. инпутом icon, которая будет эту иконку вставлять слева от ng-content. Интерфейс my-button-with-icon должен быть ровно таким же, как и у my-button. (Давайте для интереса, какой-нибудь output назначим). Покажите, как вы это через ng-content без лишних оберток сделаете.

                                                                  Совсем несложно написать свой вытягивающий метаданные из суперкласса декоратор (это же обычная функция), если вам это прямо надо.
                                                                  Вот он, воистину, angular-way! Вместо обычного class extend мне нужно пилить кастомный декоратор? Класс.
                                                                  • 0
                                                                    > И что, он теперь не функция? Более того, компонент со стейтом (даже класс, представьте) — это тоже функция от инпутов, но с сайд-эффектом в виде стейта.

                                                                    Нет, не функция. Компоненты реакта не являются чистыми функциями, они обладают состоянием (как «внешним», то есть данные используемые при рендеринге компоненты, так и «внутренним» — состояние компоненты, изменяющееся при помощи апи-хуков и по ходу lyfecycle), которое, кстати, не является иммутабельным. А «ф-я от инпутов» — это render.

                                                                    > Покажите, как вы это через ng-content без лишних оберток сделаете.

                                                                    Зачем через ng-content? Это же не HOC, сделаю через наследование:
                                                                    @Component({
                                                                        selector: "my-button",
                                                                        template: `<button (click)="clicked.emit()">{{ name }}</button>`,
                                                                    })
                                                                    export class MyButtonComponent {
                                                                        @Input() name: string;
                                                                        @Output() clicked = new EventEmitter;
                                                                    }
                                                                    
                                                                    @Component({
                                                                        selector: "my-button-with-icon",
                                                                        template: `<span>{{ icon }}</span><my-button (clicked)="clicked.emit()" [name]="name"></my-button>`,
                                                                    })
                                                                    export class MyButtonWithIconComponent extends MyButtonComponent {
                                                                        @Input() icon: string;
                                                                    }
                                                                    
                                                                    @Component({
                                                                        selector: "test-button",
                                                                        template: `<my-button-with-icon [name]="'name'" [icon]="'icon'" (clicked)="click()"></my-button-with-icon>`,
                                                                    })
                                                                    export class TestButtonComponent {
                                                                        public click() {
                                                                            console.log("Clicked!");
                                                                        }
                                                                    }
                                                                    


                                                                    Но если уж хочется через ng-content, то можно так:

                                                                    @Component({
                                                                        selector: "my-button",
                                                                        template: `<button (click)="clicked.emit()">{{ name }}</button>`,
                                                                    })
                                                                    export class MyButtonComponent {
                                                                        @Input() name: string;
                                                                        @Output() clicked = new EventEmitter;
                                                                    }
                                                                    
                                                                    @Component({
                                                                        selector: "with-icon",
                                                                        template: `<span>{{ icon }}</span><ng-content></ng-content>`,
                                                                    })
                                                                    export class WithIconComponent {
                                                                        @Input() icon: string;
                                                                    }
                                                                    
                                                                    @Component({
                                                                        selector: "test-button",
                                                                        template: `<with-icon [icon]="'icon'"><my-button [name]="'name'" (clicked)="click()"></my-button><with-icon>`,
                                                                    })
                                                                    export class TestButtonComponent {
                                                                        public click() {
                                                                            console.log("Clicked!");
                                                                        }
                                                                    }
                                                                    


                                                                    В обоих случаях все вполне себе декларативно, нет?

                                                                    > без лишних оберток

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

                                                                    > Вот он, воистину, angular-way! Вместо обычного class extend мне нужно пилить кастомный декоратор? Класс.

                                                                    Декоратор — это обычная функция. В чем проблема написать обычную функцию на 10 строк для реализации своих хотелок? Почему в реакте вы так делаете и не бухтите, а в ангуляре — нельзя?
                                                                    • 0
                                                                      Компоненты реакта не являются чистыми функциями
                                                                      Вы бы ради приличия в доки хоть заглянули

                                                                      сделаю через наследование
                                                                      Уже же вроде обсудили, не наследуется конфигурация.

                                                                      <with-icon [icon]="'icon'"><my-button [name]="'name'" (clicked)=«click()»></my-button><with-icon>
                                                                      И в чем прикол? Каждый раз таскать за собой эту конструкцию? Вы лукавите, так как задачу не решили — при попытке спрятать этот темплейт в компонент, вам придется руками прокидывать все возможные inputs/outputs до кнопки. Именно это я вам и пытался донести.

                                                                      Какое-то надуманное требование
                                                                      Требование совсем не надуманное, так как некоторые компоненты могут быть ячейками таблицы, на некоторых может стоять height: 100% и т.п. Я опережу вас и сразу скажу, что аргумент «не делать такие компоненты», потому-что «ангуляр не может», не катит. Если вы скажете использовать директивы, то я отвечу, нафига вообще эти компоненты в ангуляре.

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

                                                                      Декоратор — это обычная функция. В чем проблема написать обычную функцию на 10 строк для реализации своих хотелок? Почему в реакте вы так делаете и не бухтите, а в ангуляре — нельзя?
                                                                      И на каждом компоненте ее вызывать вместе с обычными наследованием, чтобы унаследовать еще какой-то кусок? Каких хотелок? Я ожидаю от инструмента корректной работы со стандартными языковыми конструкциями, такими как, о боги, обычное наследование, а не подмены их своими кривоработающими велосипедами. Вы что, правда считаете, что это нормально? Тут товарищ TheShock любит напоминать про Стокгольмский синдром.

                                                                      И в каком месте я это делаю в реакте?
                                                                      const Foo = props => <div>foo</div>;
                                                                      class Bar extends React.Component {
                                                                      	render() {
                                                                      		return (
                                                                      			<div>bar</div>
                                                                      		);
                                                                      	}
                                                                      }
                                                                      


                                                                      • 0
                                                                        > Вы бы ради приличия в доки хоть заглянули

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

                                                                        > Уже же вроде обсудили, не наследуется конфигурация.

                                                                        Вам никто не мешает наследовать, если хотите.

                                                                        > при попытке спрятать этот темплейт в компонент, вам придется руками прокидывать все возможные inputs/outputs до кнопки.

                                                                        Вы же таскаете с собой эту конструкцию каждый раз, когда дергаете фунарги? Или вы в выборе из двух вариантов:
                                                                        function f(x: number, y: number) {
                                                                          return x+y;
                                                                        }
                                                                        
                                                                        function g1(z: number, x: number, y: number) {
                                                                          return f(x, y) + z;
                                                                        }
                                                                        
                                                                        function g2(z: number, ...args: number[]) {
                                                                          return f.apply(args) + z;
                                                                        }
                                                                        

                                                                        вы выбираете g2? Мы тут не договоримся, потому что по моему мнению такой код не должен проходить ревью.

                                                                        > Каждый раз ее таскать за собой? Зачем вообще вся эта возня с компонентами, если такая логика не инкапсулируется?

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

                                                                        > И на каждом компоненте ее вызывать вместе с обычными наследованием, чтобы унаследовать еще какой-то кусок?

                                                                        И в чем проблема?

                                                                        > И в каком месте я это делаю в реакте?

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

                                                                        > Я ожидаю от инструмента корректной работы со стандартными языковыми конструкциями, такими как, о боги, обычное наследование, а не подмены их своими кривоработающими велосипедами.

                                                                        Он и работает корректно и ожидаемо, а ваши «хотелки» состоят в том, чтобы «было как в реакте». Это уже вопрос религиозных убеждений и обсуждать его я смысла не вижу. Вы привели выше конкретную и объективную претензию — отсутствие декларативности. И, действительно, всякие вьюрефы ей не отличаются. Я выше привел пример, как это делается без вьюрефов, с оверхедом не выше, чем в реакте. Вас это решение по уровню декларативности устраивает?
                                                                        • 0
                                                                          У вас с логикой какие-то явные проблемы. Из того, что существуют негры, которые являются людьми, следует ли, что люди — это негры? Нет. Точно так же и из того, что существуют функции, которые являются компонентами, не следует, что компоненты — это функции.
                                                                          Ну раз у вас с логикой все в порядке, поведайте миру, чем принципиально HOF отличается от HOC.

                                                                          Вам никто не мешает наследовать, если хотите.
                                                                          Сторонними средствами?

                                                                          Вы же таскаете с собой эту конструкцию каждый раз, когда дергаете фунарги?
                                                                          Вы что продать пытаетесь? Что разработчик в каждом месте должен писать <with-icon><my-button></my-button></with-icon> вместо <my-button-with-icon></my-button-with-icon>? Бред. То, что вы это делаете — еще не значит, что это верно.
                                                                          Ну в реакте же вы будете это все таскать за собой?
                                                                          Аналогично — вместо простого компонента, нужно помнить, что нужно везде лепить эту директиву. В реакте это упаковывется в компонент и используется без заморочек, что тут надо класс подоткнуть, тут директиву, а тут кастомную разметку.

                                                                          И в чем проблема?
                                                                          С тем, что это излишнее усложнение. Разработчик при экстенде должно помнить, что нужно влепить еще и кастомный декоратор. Зачем?

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

                                                                          а ваши «хотелки» состоят в том, чтобы «было как в реакте»
                                                                          Мои хотелки состоят в том, чтобы было как в языке. Без лишних сущностей. Стандартными средствами.

                                                                          Я выше привел пример, как это делается без вьюрефов, с оверхедом не выше, чем в реакте.
                                                                          Вы все-равно не видите разницу? Уложите <with-icon> и <my-button> в один компонент без наследования.

                                                                          Я вам не пытаюсь продать «не использовать ангуляр», а вы мне не пытайтесь продать «использовать ангуляр». Иначе разговор зайдет в тупик.
                                                                          Я вам описал проблему, вы проблему не решили. А только привели сомнительные примеры, как с помощью дополнительных конструкций и повышения общей сложности достичь чего-то похожего на решение.
                                                                          • 0
                                                                            > Ну раз у вас с логикой все в порядке, поведайте миру, чем принципиально HOF отличается от HOC.

                                                                            Тем, что HOF — это ф-я, которая принимает и возвращает ф-ю, а HOС — это компонент, который принимает и возвращает компонент. Да, реактовские HOС не являются полноценными, я об этом выше уже говорил.

                                                                            > Сторонними средствами?

                                                                            Почему сторонними? Вполне нативными.

                                                                            > Вы что продать пытаетесь? Что разработчик в каждом месте должен писать <with-icon><my-button></my-button></with-icon> вместо <my-button-with-icon></my-button-with-icon>?

                                                                            Ну так сделайте как в реакте, в чем проблема? Объявите компоненту <my-button-with-icon></my-button-with-icon>, которая будет раскрываться в <with-icon><my-button></my-button></with-icon>. Почему вы не используете реактовские подходы?

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

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

                                                                            > С тем, что это излишнее усложнение.

                                                                            Вызвать ф-ю — это усложнение? Вы программист, вообще?
                                                                            У меня, кстати, такой вопрос — а вы используете редакс? Явно нет. Он ведь целиком и полностью состоит из подобных «усложнений», не правда ли?

                                                                            > Ау. Вы о чем? Я про отсутствие левых декораторов и врапперов.

                                                                            Функции (они же декораторы) — входят в библиотеку Vanilla JS. Поддерживаются искаробки на всех браузерах и всех устройствах, не требуют импорта, настройки и чего бы то ни было. Какие проблемы? Почему вы используете функции в реакте, но не хотите их использовать в ангуляре?

                                                                            > Стандартными средствами.

                                                                            Функции — стандартные средства языка.

                                                                            > Вы все-равно не видите разницу?

                                                                            Я вижу разницу, конечно же. В одном случае мы забиваем гвоздь молотком, в другом — вворачиваем шуруп отверткой. Результат практически тот же.

                                                                            > Уложите <with-icon> и <my-button> в один компонент без наследования.

                                                                            Почему без наследования-то? :cry:

                                                                            > Я вам описал проблему, вы проблему не решили.

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

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

                                                                            Да я секрет открою, вы можете вообще переопределить Component и импортировать его потом из своего ../utils вместо angular/core. И никто вообще разницы не заметит.

                                                                            Я, конечно, не предлагаю это как реальное решение — но просто если вам хочется странного такого, то ради бога.
                                                                            • 0
                                                                              Тем, что HOF — это ф-я, которая принимает и возвращает ф-ю, а HOС — это компонент, который принимает и возвращает компонент.
                                                                              Ну и что? Что теперь-то? Абстракция ровно одна и та же.
                                                                              Да, реактовские HOС не являются полноценными, я об этом выше уже говорил
                                                                              Только вот непонятно, почему. И еще не понятно, с чего вы взяли, что это антипаттерн.

                                                                              Почему сторонними? Вполне нативными.
                                                                              Кастомный декоратор — это сторонние средства. Обычное наследование классов без бубнов — нативные.

                                                                              Ну так сделайте как в реакте, в чем проблема? Объявите компоненту <my-button-with-icon></my-button-with-icon>, которая будет раскрываться в <with-icon><my-button></my-button></with-icon>.
                                                                              Да потому-что придется копипастить inputs/outputs из my-button в my-button-with-icon.

                                                                              Почему вы не используете реактовские подходы?
                                                                              Потому-что они не работают в из-за сильной ограниченности «компонентов» в ангуляре.

                                                                              Вызвать ф-ю — это усложнение? Вы программист, вообще?
                                                                              У меня, кстати, такой вопрос — а вы используете редакс? Явно нет. Он ведь целиком и полностью состоит из подобных «усложнений», не правда ли?
                                                                              Вызвать лишнюю функцию — это усложнение. У вас наверное весь код состоит из ненужной лапши, подтыкающей кривую архитектуру/дизайн. Не поверите — использую и очень много. Еще больше не поверите, использую ngrx/store — что почти то же самое. И это все не вызывает недоумения при использовании, так как все по делу.

                                                                              Функции (они же декораторы) — входят в библиотеку Vanilla JS. Поддерживаются искаробки на всех браузерах и всех устройствах, не требуют импорта, настройки и чего бы то ни было. Какие проблемы? Почему вы используете функции в реакте, но не хотите их использовать в ангуляре?
                                                                              Вы на другом уровне абстракции застряли, поднимитесь. На кой черт мне какие-то обертки для наследования, если язык уже предоставляет инструмент? Та же фигня с этими NgModule — зачем мне какие-то левые конструкции, если язык уже предоставляет стандартное решение? Повторюсь, воистину, angular-way.

                                                                              Функции — стандартные средства языка.
                                                                              Аналогично.

                                                                              Я вижу разницу, конечно же. В одном случае мы забиваем гвоздь молотком, в другом — вворачиваем шуруп отверткой. Результат практически тот же.
                                                                              У вас есть опыт разработки в команде? Когда приходит новый человек, например? Вы пишите для таких ситуаций огроменные мануалы, что, когда нужно отрендерить кнопку с иконкой, на самом деле нужно отрендерить два компонента в строгом порядке, один в другом, еще и с директивой какой-нибудь? И делать это нужно каждый раз в каждом участке кода. Вместо того, чтобы взять готовый компонент, который является простейшей композицией обычной кнопки и этой несчастной иконки.

                                                                              Почему без наследования-то? :cry:
                                                                              Да потому-что обычное наследование не работает. Дополнительный декоратор — это не решение, а костыль к тому, что не работает наследование.

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

                                                                              Да я секрет открою, вы можете вообще переопределить Component и импортировать его потом из своего ../utils вместо angular/core. И никто вообще разницы не заметит.
                                                                              Потрясающе, теперь вся команда должна знать, что стандартный Component использовать нельзя, нужно использовать кастомный. И мы возвращаемся к огромному бессмысленному мануалу.
                                                                              • 0
                                                                                > Да потому-что придется копипастить inputs/outputs из my-button в my-button-with-icon.

                                                                                Инпуты/аутпуты наследуются. У меня же выше был пример с наследованием, там это видно.

                                                                                > Кастомный декоратор — это сторонние средства.

                                                                                Декоратор — это _просто функция_. Вот это:
                                                                                @Component({ ...props })
                                                                                export class FooComponent {
                                                                                    
                                                                                };
                                                                                

                                                                                ровно то же самое, что и вот это:
                                                                                class Foo {
                                                                                
                                                                                };
                                                                                
                                                                                export const FooComponent = Component({ ...props })(Foo);
                                                                                

                                                                                Когда вы на реакте применяете какую-то ф-ю к компоненту — вы фактически и используете декоратор :)
                                                                                //так вы пишите:
                                                                                const EnhancedComponent = higherOrderComponent(WrappedComponent);
                                                                                
                                                                                //а можно записать с синтаксисом декоратора:
                                                                                @higherOrderComponent
                                                                                export class WrappedComponent {
                                                                                    
                                                                                } 
                                                                                

                                                                                то есть «определить и использовать в реакте HOC» и «определить и использовать кастомный декоратор» — это _одно и то же_. HOC из реакта — это _и есть_ декораторы классов.

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

                                                                                Команда же может запомнить, что надо юзать higherOrderComponent выше? :)

                                                                                > Окей, тут соглашусь

                                                                                Значит, по факту декларативности мы вопрос утрясли.
                                                                                • 0
                                                                                  Инпуты/аутпуты наследуются. У меня же выше был пример с наследованием, там это видно.
                                                                                  Мы ходим по кругу.

                                                                                  «определить и использовать в реакте HOC» и «определить и использовать кастомный декоратор» — это _одно и то же_. HOC из реакта — это _и есть_ декораторы классов.
                                                                                  Это все очень и очень здорово. Только вот, чтобы получить кнопку с иконкой, ни декораторы, ни HOC не используются:
                                                                                  const Button = props => {
                                                                                  	const {children, onClick} = props;
                                                                                  	return (
                                                                                  		<button onClick={onClick}>{children}</button>
                                                                                  	);
                                                                                  };
                                                                                  
                                                                                  const ButtonWithIcon = props => {
                                                                                  	const {icon, children, ...rest} = props;
                                                                                  	return (
                                                                                  		<Button {...rest}>
                                                                                  			<Icon name={icon}/>
                                                                                  			{children}
                                                                                  		</Button>
                                                                                  	);
                                                                                  };
                                                                                  


                                                                                  HOC в виде декоратора используется для других целей.
                                                                                  Занимательно, что можно и ButtonWithIcon превратить в HOC, просто принимая компонент Icon через props:
                                                                                  const Button = props => {
                                                                                  	const {children, onClick} = props;
                                                                                  	return (
                                                                                  		<button onClick={onClick}>{children}</button>
                                                                                  	);
                                                                                  };
                                                                                  
                                                                                  const ButtonWithIcon = props => {
                                                                                  	const {icon, children, Icon, ...rest} = props;
                                                                                  	return (
                                                                                  		<Button {...rest}>
                                                                                  			<Icon name={icon}/>
                                                                                  			{children}
                                                                                  		</Button>
                                                                                  	);
                                                                                  };
                                                                                  


                                                                                  Ну вот что может быть удобней и проще? Никаких декораторов, костылей и подпорок — просто функции. Более того, во всех этих кнопках сохраняется стандартный браузерный интерфейс кнопки — всякие там tabindex и т.п.
                                                                                  • 0
                                                                                    Вот момент про ButtonWithIcon в качестве HOC не читайте, что-то я погорячился. Всмысле терминологически
                                                                                    • 0
                                                                                      > Никаких декораторов, костылей и подпорок — просто функции.

                                                                                      Декоратор — и есть просто функция. Мы, вроде, уже это выяснили?

                                                                                      > Это все очень и очень здорово. Только вот, чтобы получить кнопку с иконкой, ни декораторы, ни HOC не используются:

                                                                                      ну вот мой вариант был:
                                                                                      @Component({
                                                                                          selector: "my-button",
                                                                                          template: `<button (click)="clicked.emit()">{{ name }}</button>`,
                                                                                      })
                                                                                      export class MyButtonComponent {
                                                                                          @Input() name: string;
                                                                                          @Output() clicked = new EventEmitter;
                                                                                      }
                                                                                      
                                                                                      @Component({
                                                                                          selector: "my-button-with-icon",
                                                                                          template: `<span>{{ icon }}</span><my-button (clicked)="clicked.emit()" [name]="name"></my-button>`,
                                                                                      })
                                                                                      export class MyButtonWithIconComponent extends MyButtonComponent {
                                                                                          @Input() icon: string;
                                                                                      }
                                                                                      

                                                                                      то же самое ведь?

                                                                                      > Мы ходим по кругу.

                                                                                      Нет, они сами по себе наследуются. Без «кастомных декораторов» и всего такого:
                                                                                      export class MyButtonWithIconComponent extends MyButtonComponent {
                                                                                          @Input() icon: string;
                                                                                      }
                                                                                      
                                                                                      • 0
                                                                                        Декоратор — и есть просто функция. Мы, вроде, уже это выяснили?
                                                                                        Это и выяснять не надо было. Разговор был о целесообразности, а не о классификации.

                                                                                        то же самое ведь?
                                                                                        Совсем не то же самое. Иконка должна быть внутри my-button. И даже если запихнуть span внутрь my-button в темплейте my-button-with-icon, у вас появляются ненужные обертки (возвращаемся к проблеме наличия оберток). Кроме того, если у кнопки есть стили, а в 99% случаев они есть, то они не наследуются. Был заведен тикет, но по традиции его быстро закрыли.

                                                                                        Более того, если вы в базовой кнопке добавили input/output — вам нужно пойти во все наследники и руками пробросить это все в шаблоне (как в случае с пробросом clicked).

                                                                                        Нет, они сами по себе наследуются. Без «кастомных декораторов» и всего такого. См. выше.
                                                                                        По кругу мы ходим из-за проблем ненаследования метаданных, а не наследования inputs/outputs.
                                                                                        • 0
                                                                                          > Это и выяснять не надо было. Разговор был о целесообразности, а не о классификации.

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

                                                                                          > По кругу мы ходим из-за проблем ненаследования метаданных, а не наследования inputs/outputs.

                                                                                          Тогда к чему вы приплели inputs/outputs?

                                                                                          > вам нужно пойти во все наследники и руками пробросить это все в шаблоне (как в случае с пробросом clicked).

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

                                                                                          > Кроме того, если у кнопки есть стили, а в 99% случаев они есть, то они не наследуются.

                                                                                          Так это правильно. Они легко могут сломаться, если их отнаследовать.

                                                                                          > Совсем не то же самое. Иконка должна быть внутри my-button.

                                                                                          Так бы сразу и сказали, я же не могу мысли читать:
                                                                                          @Component({
                                                                                              selector: "my-button",
                                                                                              template: `<button (click)="clicked.emit()"><ng-content></ng-content></button>`,
                                                                                          })
                                                                                          export class MyButtonComponent {
                                                                                              @Input() name: string;
                                                                                              @Output() clicked = new EventEmitter;
                                                                                          }
                                                                                          
                                                                                          @Component({
                                                                                              selector: "my-button-with-icon",
                                                                                              template: `<my-button (clicked)="clicked.emit()" [name]="name"><span>{{ icon }}</span></my-button>`,
                                                                                          })
                                                                                          export class MyButtonWithIconComponent extends MyButtonComponent {
                                                                                              @Input() icon: string;
                                                                                          }
                                                                                          

                                                                                          так?
                                                                                          • 0
                                                                                            Ну вы согласны тогда, что писать свои метаредьюсеры нецелесообразно? И hoc в реакте — тоже? Если да, то тогда ваша позиция понятна. Если нет — то тогда тут наблюдается явная непоследовательность.
                                                                                            Вы в упор меня не слышите, и складывается впечатление, что специально. Целесообразно использовать инструмент для решения задачи, но нецелесообразно лепить костыли для решения проблемы в дизайне. Вот что мешало включить всю конфигурацию декоратора в тело класса? Желание быть похожими на джаву с аттрибутами? Мнимая «переиспользуемость» классов отдельно от этих декораторов? Я вообще ни разу не видел класс отдельно от декоратора. Зачем вообще тогда эти декораторы? Создали бы интерфейс IComponent и своим чудо-шаблонизатором проверяли бы все используемые в шаблоне компоненты.

                                                                                            Тогда к чему вы приплели inputs/outputs?
                                                                                            Это вы их приплели. Я вам про то, что метаданные не наследуются и наследование не подходит — вы мне про то, что inputs/outputs наследуются, так что можно использовать наследование. Я вам про то, что метаданные не наследуются, ну и так далее…

                                                                                            Это сродни претензии к тому, что если вы в функцию добавили аргумент, то надо везде, где эта функция вызывается, добавить этот аргумент. Я тут ничего плохого не вижу.
                                                                                            Нет, не сродни. Мы говорим о наследовании, а не о композиции. Если ButtonWithIcon наследует Button, то подразумевается что все поведение, вплоть до работы с EventEmitter наследуется, а не копипастится. Иначе грош цена такому наследованию, и нужно использовать композицию. А с рендерингом на уровне хоста без обертки у ангуляра проблемы.

                                                                                            Так это правильно. Они легко могут сломаться, если их отнаследовать.
                                                                                            Прикольно. Вот наследуете вы кнопку, добавляете какие-нибудь хуки туда, метаданные не трогаете. И все, новая кнопка без стилей и маркапа.

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

                                                                                            Вот чего припираемся-то? Мой посыл в том, что дизайн кривой, пользоваться неудобно, проблемы есть. Вы пытаетесь меня переубедить или что? Что дизайн оправдан? Нет. Что пользоваться удобно? Нет. Проблем нет? Хм, нет.
                                                                                            • 0
                                                                                              > Вы в упор меня не слышите, и складывается впечатление, что специально. Целесообразно использовать инструмент для решения задачи, но нецелесообразно лепить костыли для решения проблемы в дизайне.

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

                                                                                              > Вот что мешало включить всю конфигурацию декоратора в тело класса?

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

                                                                                              > Мнимая «переиспользуемость» классов отдельно от этих декораторов?

                                                                                              Вот, кстати, да. Если желаете — можете вынести конфигурацию декоратора и переиспользовать ее в разных классах (наследниках, например). И никаких «кастомных декораторов».

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

                                                                                              Нет, не понял. Ваш пример на реакте был уже позже, я когда его увидел — то переделал.

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

                                                                                              Удобство — это субъективная категория. Я не вижу какой-либо разницы по сравнению с реактом. Мне, например, jsx не удобен и кривое разделение ответственности (ну тут, собственно, проблема в том, что реакт — не фреймворк, а библиотека, и для нормальной работы так же как и редакс предполагается дорабатывать его напильником, так что все так и должно быть).

                                                                                              > Нет, не сродни.

                                                                                              Это ваше мнение.

                                                                                              > Мы говорим о наследовании, а не о композиции. Если ButtonWithIcon наследует Button, то подразумевается что все поведение, вплоть до работы с EventEmitter наследуется, а не копипастится.

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

                                                                                              > Что дизайн оправдан? Нет.

                                                                                              Это ваше мнение. Единственную вашу объективную претензию мы рассмотрели, если других таких же нету — я не вижу смысла продолжать. Потому что «здесь вызов функции — использование инструмента, а там — костыль» или «оно врапает а я хочу чтобы не врапало» — это не разговор.
                                                                                              • 0
                                                                                                То что мы обсуждаем — и есть обычное использование инструмента для решения задачи. Мне непонятно, почему вы готовы писать обычные функции в реакте, но против того, чтобы делать то же самое в ангуляре в точно том же самом контексте.
                                                                                                @Component({
                                                                                                	selector: 'my-button',
                                                                                                	style: ':host { background: red }',
                                                                                                	template: '<button></button>'
                                                                                                })
                                                                                                class Button {
                                                                                                }
                                                                                                
                                                                                                @InheritMetadata()
                                                                                                @Component({
                                                                                                	selector: 'my-custom-button',
                                                                                                	style: ':host { background: green }'
                                                                                                })
                                                                                                class CustomButton extends Button {}
                                                                                                

                                                                                                Вы считаете целесообразным лепить InheritMetadata в каждом компоненте, чтобы помочь наследованию сделать дело? Если да, то пора заканчивать этот разговор, к согласию мы не придем.
                                                                                                То, что это просто нельзя сделать сколько-нибудь осмысленным образом.
                                                                                                Что мешает template, style и компанию складывать в class properties? B вся компания дружно унаследуется. И работать с ними можно будет стандартными средствами языка.
                                                                                                Те метаданные, что имеет смысл наследовать, наследуются. А те, что наследовать нельзя — не наследуются.
                                                                                                Не наследуются все метаданные.
                                                                                                Ни стили, ни темплейты, ни другие подобные вещи наследовать просто нельзя, это чревато серьезными проблемами.
                                                                                                В каком-то вы странном мире живете. Поясните, какими проблемами? Наследуя компонент кнопку я не могу унаследовать цвет ее фона?
                                                                                                То есть, эту фичу невозможно сделать так, чтобы она не была заведомо поломанной.
                                                                                                Зачем вообще тогда использовать декораторы? Выстроили бы обычную иерархию для наследования, как везде делали много лет.
                                                                                                Вот, кстати, да. Если желаете — можете вынести конфигурацию декоратора и переиспользовать ее в разных классах (наследниках, например). И никаких «кастомных декораторов».
                                                                                                Вот вы упертый. Вместо наследования теперь нужно грузить какие-то доп. вещи из компонента. Это все-равно костыль. Плюс возвращаемся к первому пункту.
                                                                                                Удобство — это субъективная категория.
                                                                                                Ну то есть про дизайн и проблемы вы согласны? Давайте резюмировать уже
                                                                                                Не наследуется шаблон, потому что его нельзя осмысленно наследовать
                                                                                                Святая корова, да почему?? Шаблон все-равно компайлится в рантайме, какая разница к какой модели (ComponentClass) он будет привязан — к родителю или к потомку? Если возникнет ошибка — то она просто возникнет и все.
                                                                                                Потому что «здесь вызов функции — использование инструмента, а там — костыль» или «оно врапает а я хочу чтобы не врапало» — это не разговор
                                                                                                Ну если вы не видите, в чем заключается проблема наличия «врапает», хотя это уже объяснялось, то это совсем бесполезный разговор. Вы не можете решить проблему, так как она не решаема, либо решаема но с костылями, что вы никак усвоить не можете.
                                                                                                я не вижу смысла продолжать
                                                                                                На этом закончим.
                                                                                                • 0
                                                                                                  > Вы считаете целесообразным лепить InheritMetadata в каждом компоненте, чтобы помочь наследованию сделать дело?

                                                                                                  В реакте все постоянно так делают и никаких проблем это не вызывает. Это во-первых. Во-вторых — метаданные из Component наследоваться и не должны, так что нет, _я_ не предлагаю. Это _вы_ предлагаете такое поведение. Я вам лишь указал, как вы можете его достичь — это делается абсолютно бесплатно, переопределением декоратора.

                                                                                                  > Что мешает template, style и компанию складывать в class properties?

                                                                                                  Ничего не мешает. Но это не будет работать.

                                                                                                  > Не наследуются все метаданные.

                                                                                                  А зависимости, видать, инжектятся в потомках за счет святого духа? А инпуты /оутпуты базового класса откуда берутся? Или вы не в курсе, что это все — тоже метаданные?

                                                                                                  > Ну то есть про дизайн и проблемы вы согласны?

                                                                                                  Вы же пока не назвали проблем.

                                                                                                  > Святая корова, да почему??

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

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

                                                                                                  Далее вы хотите сделать все более молодежно и модно. По SOLID. У вас ведь вид привязан к модели — а это нехорошо. Вы их развязываете — теперь у вас вид зависит не от модели, а от ее интерфейса, а конкретная модель инжектится. А какая модель? Неизвестно — теперь вид ничего не знает о конкретной модели. Значит, нужна конфигурация, и в ней у вас будет написано что-то вроде: «модель Х рендерится видом Y». И если вы хотите отнаследовать одну компоненту от другой — то это сразу не заработает, вам надо пойти и добавить соответствующее вхождение в конфиг, чтобы связать вид с моделью. Как в ангуляре.

                                                                                                  Потом проходит некоторое время и оказывается, что ваша конфигурация превратилась в огромную портянку. Да и вообще — прыгать туда-сюда, чтобы узнать что там к чему инжектится и с чем связано — не совсем удобно. Вы распиливаете вашу конфигурацию на куски — по куску на модель — и каждый кусок, соответствующий конфигурации модели, храните вместе с моделью. А конфигуратор потом собирает из этих кусков исходный полный конфиг. И у вас получается архитектура ангуляра. В ангуляре все вышеобозначенные шаги сделаны — потому что это фреймворк. У него есть архитектура. Реакт — это библиотека, в ней архитектуры нет. Предполагается, что ее надо создавать самому для конкретного приложения. И когда вы ее создадите, то точно так же у вас вид будет отделен от модели и будет отдельно наследоваться…
                                                                                                  • 0
                                                                                                    Спасибо за дельное разъяснение, вот сразу бы так, теперь понятно. Но, мне как человеку, пришедшему из реакта, не шибко понятна цель этой возни с ненаследуемыми шаблонами, прибиваемыми к наследуемым моделям. Какая-то архитектура ради архитектуры. Смотрите следующую цитату:
                                                                                                    и если вы отнаследуете модель — то не получите нового компонента.
                                                                                                    И когда вы ее создадите, то точно так же у вас вид будет отделен от модели и будет отдельно наследоваться
                                                                                                    Но если я в реакте «наследую» (расширяю через враппер со спредом, но без лишней дом-ноды) «вид» (компонент), то я получу новый компонент. Со старой моделью. Или с новой — это уже как решу, модель будет приниматься прекрасно через props, либо браться дефолтная. С TS можно еще и ее интерфейс проверить. Видите, к чему я? Почему меня заведомо лишают этой гибкости?

                                                                                                    Вы же пока не назвали проблем.
                                                                                                    Проблему я назвал — мне нужно расширить кнопку (окей, компонент строки таблицы) без доп. обертки
                                                                                                    из коробки, так как, забавно, есть с чем сравнивать. Я же из этих сравнений исхожу, а не с потолка беру такие требования.
                                                                                                    • 0
                                                                                                      > Но если я в реакте «наследую» (расширяю через враппер со спредом, но без лишней дом-ноды) «вид» (компонент), то я получу новый компонент. Со старой моделью.

                                                                                                      Ну кто вас какой гибкости лишает? Вы точно так же можете создать новый вид и связать его с расширением старой модели (с добавленным property «icon»), именно это и происходит в моем примере выше. Просто в реакте вы не делаете второй шаг (не описываете связывание), так как модель не выделена, связывать нечего, не с чем, а потому и не нужно. В реакте у вас есть возможность определить компоненту, как единую сущность. В ангуляре — нет. В ангуляре всегда есть разделение на вид и модель и всегда нужно описать их связь. И вы _можете_ сделать так, чтобы эта связь формировалась определенным образом автоматически (@ComponentInherit ваш), но это не является дефолтным поведением.

                                                                                                      > Проблему я назвал — мне нужно расширить кнопку (окей, компонент строки таблицы) без доп. обертки

                                                                                                      Ну а если я скажу, что мне надо тоже сделать кнопку, но с оберткой? Будут костыли уже в реакте. Я согласен, что иногда (весьма редко) действительно надо без оберток. Тогда компонент применяется атрибут-селектором и все, так что проблема полностью надуманна.
                                                                                                      • 0
                                                                                                        Ну а если я скажу, что мне надо тоже сделать кнопку, но с оберткой? Будут костыли уже в реакте.
                                                                                                        Прекрасно — декларативно добавьте свою обертку в разметку. Это же не костыль. Костыль — это unwrap в директиве.
                                                                                                        Тогда компонент применяется атрибут-селектором и все, так что проблема полностью надуманна.
                                                                                                        Судя по офф-докам, так делать не стоит. Кроме того, использовать компонент по аттрибуту на уже существующем компоненте ангуляр не дает из-за конфликта имен. Директива не подходит из-за стилей. Получается двояко — для обычных (нативных) компонентов нужно использовать аттрибут-селекторы, для ненативных — директивы. Так себе, но окей. Но остается последний вариант — когда нужно расширить кастомный компонент без обертки.
                                                                                                        • 0
                                                                                                          > Прекрасно — декларативно добавьте свою обертку в разметку. Это же не костыль.

                                                                                                          Это мне для каждой директивы обертку добавлять? :D
                                                                                                          ;)

                                                                                                          > Судя по офф-докам, так делать не стоит. Кроме того, использовать компонент по аттрибуту на уже существующем компоненте ангуляр не дает из-за конфликта имен.

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

                                                                                                          > Но остается последний вариант — когда нужно расширить кастомный компонент без обертки.

                                                                                                          Если у нас кастомный компонент, то тогда нет проблем его обертывать.
                                                                                                          • 0
                                                                                                            Это мне для каждой директивы обертку добавлять? :D
                                                                                                            ;)
                                                                                                            Вы на что намекаете? Что удалять лишний враппер — это ок. А добавить — нет?

                                                                                                            тогда нет проблем его обертывать.
                                                                                                            Увы, есть. Например есть сетка, внутри которой сидят виджеты. Виджетам проставлена высота 100%, чтобы они растягивались по высоте ячеек сетки. Тут появляется необходимость заменить виджеты контейнерами, которые могут сами подгружать данные. И тут мы идем в контейнер, лепим ему стили, лепим туда детали реализации компонента, который он оборачивает, а именно высоту 100%. Нет, мне конечно не сложно прописать там везде dispay: block; height: 100% — но это же нарушает инкапсуляцию компонента.
                                                                                                            Да, я не спорю, можно контейнер сделать в виде директивы. Но почему-то мне это кажется не решением, а уходом от проблемы, когда в виде компонента, в силу неведомых ограничений движка контейнер не сделать. Опять же, это все навеяно уже работающими подходами в реакте.
                                                                                                            • 0
                                                                                                              > Вы на что намекаете? Что удалять лишний враппер — это ок. А добавить — нет?

                                                                                                              Это я намекая на ваши претензии вида: «это мне на каждую компоненту @Inheritance ставить? оО».

                                                                                                              > Увы, есть.

                                                                                                              Не совсем понял ваше объяснение. :host селектор проблему не решает?
                                                                                                              • 0
                                                                                                                Это я намекая на ваши претензии вида: «это мне на каждую компоненту @Inheritance ставить? оО».
                                                                                                                Вы не видите разницы? Печаль.

                                                                                                                Не совсем понял ваше объяснение. :host селектор проблему не решает?
                                                                                                                Решает, я к тому и веду, в контейнере пишем эти стили в :host. Но только выходит, чтобы заработал компонент, в контейнере мне нужно знать как именно его починить — добавить высоту. Тогда как контейнер не отвечает за ui.
                                                                                                                • 0
                                                                                                                  > Тогда как контейнер не отвечает за ui.

                                                                                                                  Если он за ui не отвечает, то он и разметки содержать не должен, а значит — это attribute directive, а не component:
                                                                                                                  > Attribute directives—change the appearance or _behavior_ of an element, component, or another directive.
                                                                                                                  • 0
                                                                                                                    Директива? Вы забыли про height: 100%?
                                                                                                                    • 0
                                                                                                                      То есть, он все-таки отвечает за уи?
                                                                                                                      • 0
                                                                                                                        Отвечает из-за корявости ангуляра — тадааам — отсутствия HOC. Приходится ручками рендерить компонент в разметке контейнера и напихивать ему нужные инпуты, попутно этом же контейнере разбирая стримы из стора.
                                                                                                                        И не надо тут петь, что раз уж минимально отвечает, значит надо лепить туда стили. Стили в контейнере — это костыль для работоспособности компонента.
                                                                                                                        • 0
                                                                                                                          Я не понял. И так, у вас есть компонент, у компонента какие-то пропсы. Вы хотите сделать в точности такой же компонент с таким же видом, но чтобы в нем не было пропсов, а он сам подгружал данные (с сервера, редаксом, еще как -либо — не важно)? Все так? Тогда делаете attribute directive и выставляете инпуты хоста через @HostBinding, нет?
                                                                                                                          • 0
                                                                                                                            Да, я не спорю, можно контейнер сделать в виде директивы. Но почему-то мне это кажется не решением, а уходом от проблемы, когда в виде компонента, в силу неведомых ограничений движка контейнер не сделать. Опять же, это все навеяно уже работающими подходами в реакте.


                                                                                                                            UPD: Кстати, а HostBinding поддерживает async pipe?
                                                                                                                            • 0
                                                                                                                              > Но почему-то мне это кажется не решением

                                                                                                                              Ну это странное мнение, учитывая что attribute directives предназначены _именно_ для решения таких проблем. То есть вот он инструмент специально для этого заточенный.

                                                                                                                              > UPD: Кстати, а HostBinding поддерживает async pipe?

                                                                                                                              В каком смысле? Пайпы же находятся в темплейте. Если вы хотите сделать так, чтобы какоето проперти, которое использовалось без асинка, начало использоваться как бы с асинком — то насколько я знаю, так нельзя, надо делать subscribe и менять обычное значение. Но если оно и так уже было с асинком — то вы можете засунуть туда observable.
                                                                                                                              • 0
                                                                                                                                В каком смысле? Пайпы же находятся в темплейте.
                                                                                                                                Ну по аналогии. Да, именно это и хочется — чтобы HostBinding сам распаковывал Observable. Компоненты не знают про входящие стримы. Не шибко удобно конечно руками подписываться на стримы, пихать руками значения в поля, потом еще руками отписываться от этих подписок.
                                                                                                                                • 0
                                                                                                                                  Надо просто во все инпуты, где пробрасываются именно данные (а не константы/конфиги) делать по дефолту обсерваблами (и, с-но, асинк в темплейте). Это даже не то что для таких вот случаев, а в принципе архитектура ангуляра заточена больше под такой flow, он в целом будет удобнее (хотя поначалу и непривычно).
                                                                                                                                  • 0
                                                                                                                                    Хм, а действительно ведь.
                                                                                                                                    Вот прямо сейчас пишу код и ловлю себя на мысли, что не первый раз уже Input обратно в Observable упаковываю через ngOnChanges. И каждый раз думаю, ну что за херня-то, ну как так-то.
                                                                                                                                    • 0
                                                                                                                                      Druu
                                                                                                                                      Погодите-ка, а как из этой директивы к Output компонента прицепиться-то?
                                                                                                                                      • 0
                                                                                                                                        Druu Ну и просто киллер. И вот так там куда ни сунься =(
                                                                                                                                        • –1
                                                                                                                                          Druu Вишенка на торте — заиплеменчено это скорей всего не будет. Так что, упс, ангуляр опять превратился в тыкву =(
                                                                                                                                          • 0
                                                                                                                                            raveclassic и, собственно, вы же можете поступить как в реакте — то есть написать ф-ю, которая принимает один класс (модель), и возвращает новый — с измененным поведением. Вам только надо будет явно связать эту модель со старым видом, и все:
                                                                                                                                            const template = `<div><button>{{ name }}</button></div>`;
                                                                                                                                            
                                                                                                                                            @Component({
                                                                                                                                                selector: "my-button",
                                                                                                                                                template: template,
                                                                                                                                            })
                                                                                                                                            export class MyButtonComponent {
                                                                                                                                                 @Input() name = "";
                                                                                                                                            }
                                                                                                                                            
                                                                                                                                            export function loaded(component: any) {
                                                                                                                                                return class extends component {
                                                                                                                                                    name = "loaded";
                                                                                                                                                };
                                                                                                                                            }
                                                                                                                                            
                                                                                                                                            @Component({
                                                                                                                                                selector: "loaded-button",
                                                                                                                                                template: template,
                                                                                                                                            })
                                                                                                                                            export class LoadedButtonComponent extends loaded(MyButtonComponent) {};
                                                                                                                                            
                                                                                                                                            • 0
                                                                                                                                              Зачем вообще этот loaded? Можно же просто наследовать.
                                                                                                                                              Плюс у меня есть смутные подозрения, что, выносят темплейт из класса, мы теряем всяческую помощь IDE внутри этого темплейта. А все ради чего? Чтобы угодить дизайну движка, мол, вьюха должна лежать отдельно от компонента. Хотя они блин все-равно тут же связываются воедино. Зачем должна, кому должна, какие это проблемы в реальности решает — не понятно.
                                                                                                                                              • 0
                                                                                                                                                > Зачем вообще этот loaded?

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

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

                                                                                                                                                В тайпскрипте уже сделали language-service, так что это не проблема теперь.

                                                                                                                                                > Зачем должна, кому должна,

                                                                                                                                                Человеческой архитектуре. В реакте-то вы все равно к той же схеме придете, так какая разница.
                                                                                                                                                • 0
                                                                                                                                                  Человеческой архитектуре. В реакте-то вы все равно к той же схеме придете, так какая разница.
                                                                                                                                                  Сохранив при этом компонуемость в том виде, в котором мне нужно. А не с ворохом костылей в угоду «человеческой архитектуре». Я не вижу ни одной причины гоняться за мнимым отделением шаблона от его компонента, тем более, что по отдельности от них все-равно никакой пользы. Точно так же как вы, видимо, не видите смысла в обратном.

                                                                                                                                                  Вопрос дизайна и подхода — текущий не дает мне нужной гибкости, которую дает реакт. Я вообще всю эту ветку начал с личного впечатления, но нет, начались какие-то невразумительные попытки описать как простейшие в реакте вещи сделать с огородом костылей в 20 раз сложнее на ангуляре. Зачем? Не пойму.
                                                                                                                                                  • –1
                                                                                                                                                    > Сохранив при этом компонуемость в том виде, в котором мне нужно.

                                                                                                                                                    Ну как же вы сохраните? Вид и модель будут отдельно? Будут.

                                                                                                                                                    > Я не вижу ни одной причины гоняться за мнимым отделением шаблона от его компонента

                                                                                                                                                    А вы в реакте всю логику суете прям в компонент, таким вот невнятным ворохом? Ну тогда ясно все.

                                                                                                                                                    > Вопрос дизайна и подхода — текущий не дает мне нужной гибкости, которую дает реакт.

                                                                                                                                                    Как не дает, если гибкость решения на ангуляре наоборот _выше_? Все, что можно на реакте — можно легко повторить на ангуляре. Но вот если я начну просить ангуляровские вещи повторить на реакте — у вас это просто вообще не выйдет, тут сработает аналог правила Гринспена :)

                                                                                                                                                    > как простейшие в реакте вещи сделать с огородом костылей в 20 раз сложнее на ангуляре

                                                                                                                                                    Ну у вас проблема в том, что вы не понимаете архитектуры ангуляра и называете «костылями» пару строчек вполне идеоматического кода. Вы пытаетесь задаунгрейдить ангуляр до примитивного уровня реакта, где просто ничего нет. Это знаете, как сравнивать какой-нибудь ЯВУ с ассемблером. Приходит человек и говорит: «а вот я хочу параметр через стек передать для вызова подпрограммы. В ассемблере пишу две строчки и все работает — push/pop, а как у вас, в java/c#/javascript/etc? Ой какой ужас в 20 раз сложнее». Примерно так для меня ваши тезисы выглядят, если честно.
                                                                                                                                                    • 0
                                                                                                                                                      Ну как же вы сохраните? Вид и модель будут отдельно? Будут.
                                                                                                                                                      Компонуемость вида в том виде, в котором она мне нужна — без оберток, наследований, HOC и прочей чепухи.
                                                                                                                                                      const Button = ({chilldren}) => (
                                                                                                                                                        <button>{props.children}</button>;
                                                                                                                                                      );
                                                                                                                                                      const ButtonWithIcon = ({icon, ...props}) => (
                                                                                                                                                        <Button {...props}><Icon name={name}/>{props.children}</Button>;
                                                                                                                                                      );
                                                                                                                                                      
                                                                                                                                                      Все. Просто можно выполнять задачу легко, быстро и поддерживаемо, а можно до посинения обмазываться архитектурой.

                                                                                                                                                      А вы в реакте всю логику суете прям в компонент, таким вот невнятным ворохом? Ну тогда ясно все.
                                                                                                                                                      Если мне понадобиться вынести логику в «модель», я вынесу и буду принимать ее через props. Если нужно вынести еще дальше — есть контекст. А если еще дальше — я поставлю inversifyjs и буду инжектить ее прямо в компонент/контейнер. Все. А можно продолжать обмазываться архитектурой.

                                                                                                                                                      Как не дает, если гибкость решения на ангуляре наоборот _выше_? Все, что можно на реакте — можно легко повторить на ангуляре. Но вот если я начну просить ангуляровские вещи повторить на реакте — у вас это просто вообще не выйдет, тут сработает аналог правила Гринспена :)
                                                                                                                                                      Ну давайте, жгите!

                                                                                                                                                      Ну у вас проблема в том, что вы не понимаете архитектуры ангуляра и называете «костылями» пару строчек вполне идеоматического кода
                                                                                                                                                      Проблема у вас, так как вы принимаете откровенно хреновый дизайн за должное. «Вполне» идиоматический код — это код, который несет полезную нагрузку, а не является следствием корявой архитектуры. См. пункт выше — жгите!

                                                                                                                                                      Вы пытаетесь задаунгрейдить ангуляр до примитивного уровня реакта, где просто ничего нет
                                                                                                                                                      Хахаха, ау! Даунгрейдить ангуляр до ui-библиотеки? Максимум дубовую ui-составляющую. См. пункт выше — жгите!

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

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

                                                                                                                                                        > Если мне понадобиться вынести логику в «модель», я вынесу и буду принимать ее через props.

                                                                                                                                                        Ну так продемонстрируйте. На однострочниках-то все всегда хорошо :)

                                                                                                                                                        > А если еще дальше — я поставлю inversifyjs и буду инжектить ее прямо в компонент/контейнер. Все.

                                                                                                                                                        Ну так вы не стесняйтесь, продемонстрируйте то, о чем сейчас так лихо рассказали. Я же не так просто правило Гринспена вспомнил :)

                                                                                                                                                        > Ну давайте, жгите!

                                                                                                                                                        Давайте с чего-нибудь простого начнем. Сделайте мне аналог компоненты с селектором-атрибутом.
                                                                                                                                                        • 0
                                                                                                                                                          Ну а теперь перепишите это к нормальному виду, для полноценной задачи, чтобы бизнес-логика была вынесена в отдельный класс хотя бы.
                                                                                                                                                          Что переписывать-то? Какую логику? Логику установки иконки в кнопке?

                                                                                                                                                          Ну так продемонстрируйте. На однострочниках-то все всегда хорошо :)
                                                                                                                                                          См. пункт выше.

                                                                                                                                                          Ну так вы не стесняйтесь, продемонстрируйте то, о чем сейчас так лихо рассказали. Я же не так просто правило Гринспена вспомнил :)
                                                                                                                                                          Ну так а вы не стесняйтесь подкрепить свои заявления делом. Мало того, что вы на ангуляре не пришли к решению задачи с кнопками в таком же виде, как она решена на реакте. Так еще и заявляете, что гибкость библиотек ниже, чем «гибкость» дубового двигла с плохим дизайном.

                                                                                                                                                          Сделайте мне аналог компоненты с селектором-атрибутом.
                                                                                                                                                          Я не понял, что вы имеет в виду. Можете пример на ангуляре, чтобы понятней было?

                                                                                                                                                          • 0
                                                                                                                                                            > Что переписывать-то? Какую логику? Логику установки иконки в кнопке?

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

                                                                                                                                                            > Я не понял, что вы имеет в виду. Можете пример на ангуляре, чтобы понятней было?

                                                                                                                                                            Ну attribute directive, мы же о них сейчас как раз говорили.

                                                                                                                                                            > Мало того, что вы на ангуляре не пришли к решению задачи с кнопками в таком же виде, как она решена на реакте.

                                                                                                                                                            С чего вы взяли, что она должна решаться _в таком же виде_? Главное, чтобы не сложнее, а в таком или не таком — уже не важно.
                                                                                                                                                            • 0
                                                                                                                                                              В реальном мире у большинства компонент есть нетривиальная логика.
                                                                                                                                                              Вы про стейт компонента или что? Ну выносите операции над стейтом в функции вида state => state и передавайте их в setState. Когда будете их тестировать, вам даже компонент маунтить не нужно.

                                                                                                                                                              Ну attribute directive, мы же о них сейчас как раз говорили.
                                                                                                                                                              Аттрибутные директивы введены только как костыль для решения проблемы лишних оберток. Если бы компоненты ангуляра могли рендерить другие в качестве хоста (к слову, как это было в первом), директив бы не было вообще (как в первых RC, если мне не изменяет память).
                                                                                                                                                              Если вам нужно доп. поведение — HoC, враппер. Но раз уж просите —
                                                                                                                                                              const Component = ({color, children}) => <div style={{color: color}}>{children}</div>;
                                                                                                                                                              const HighlightHOC = color => Target => props => <Target color={color} {...props}/>;
                                                                                                                                                              const HighlightWrapper = ({color, ...props}) => <Component color={color} {...props}/>;
                                                                                                                                                              
                                                                                                                                                              const HighlightedComponent = HighlightHOC('red')(Component);
                                                                                                                                                              
                                                                                                                                                              const render = props => (
                                                                                                                                                                  <div>
                                                                                                                                                                      <HighlightedComponent>
                                                                                                                                                                          content
                                                                                                                                                                      </HighlightedComponent>
                                                                                                                                                                      <HighlightWrapper color="red">
                                                                                                                                                                          content
                                                                                                                                                                      </HighlightWrapper>
                                                                                                                                                                  </div>
                                                                                                                                                              );
                                                                                                                                                              
                                                                                                                                                              React декларативен, и не позволяет руками «патчить» компоненты из директив, как это делает ангуляр. Когда в то же время достигается совершенно тот же эффект. Но если вам совсем уж надо — есть ref, findDOMNode и все вытекающие.

                                                                                                                                                              С чего вы взяли, что она должна решаться _в таком же виде_? Главное, чтобы не сложнее, а в таком или не таком — уже не важно.
                                                                                                                                                              С того, что я изначально так ставил задачу.

                                                                                                                                                              Главное, чтобы не сложнее
                                                                                                                                                              Сравните, пожалуйста, примеры выше еще разок.

                                                                                                                                                              • 0
                                                                                                                                                                > Вы про стейт компонента или что? Ну выносите операции над стейтом в функции вида state => state и передавайте их в setState.

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

                                                                                                                                                                > Аттрибутные директивы введены только как костыль для решения проблемы лишних оберток.

                                                                                                                                                                Все несколько наоборот. Это реакт сам по себе был придуман как костыль для портирования сервер-сайд логики с php на клиент. Оттуда jsx (старательно мимикрирующий в своей семантике под php), оттуда принцип «перерендерить все» (именно это происходит при классическом запросе браузера к серверу — сервер вам генерит каждый раз всю страницу заново), отсюда vdom (чтобы этот подход не слишком сильно тормозил), изоляция стейта да и все остальное.

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

                                                                                                                                                                Так в первом ангуляре тоже были аттрибут-селекторы, несмотря на наличие replace.

                                                                                                                                                                > Но раз уж просите —

                                                                                                                                                                Вы просто лишний аргумент добавили, я же совсем не то просил. Сделайте аналог аттрибут-директивы, которая будет каждую секунду, например, менять background хоста: черный-красный-черный-красный и т.д.

                                                                                                                                                                Чтобы я мог вместо <Component/> написать <Component blink/> — и оно у меня мигает.

                                                                                                                                                                > Когда в то же время достигается совершенно тот же эффект.

                                                                                                                                                                Так я же процитирую вас:
                                                                                                                                                                > к решению задачи с кнопками _в таком же виде, как она решена на реакте_.

                                                                                                                                                                Вот и я вас прошу не достичь «такого же эффекта», а решить в том же виде, как на ангуляре. Просто потому, что я «изначально так поставил задачу».

                                                                                                                                                                > Но если вам совсем уж надо — есть ref, findDOMNode и все вытекающие.

                                                                                                                                                                Ну нет, это не по правилам. Вы же не разрешали писать кастомные декораторы? Значит, никаких refов с findDOMNode — это все ненативно, бяка и т.д., какие вы там аргументы приводили против подобных решений.

                                                                                                                                                                > Сравните, пожалуйста, примеры выше еще разок.

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

                                                                                                                                                                  Это реакт сам по себе был придуман как костыль для портирования сервер-сайд логики с php на клиент
                                                                                                                                                                  Просто в слезы! :rofl:

                                                                                                                                                                  Оттуда jsx (старательно мимикрирующий в своей семантике под php)
                                                                                                                                                                  Вы до сих пор живете внутри html-шаблона, тогда как jsx !== html. К моему великому сожалению, xml-подобный синтаксис там введен только чтобы облегчить переход вот таких вот html-щиков.

                                                                                                                                                                  «перерендерить все» (именно это происходит при классическом запросе браузера к серверу
                                                                                                                                                                  оттуда принцип «перерендерить все»
                                                                                                                                                                  Принцип этот не оттуда, а от того, что проще выкинуть трекинг зависимостей кусков разметки от кусков модели. state => ui — все. Это более высокий уровень абстракции. То, что в реальности происходят какие-то доп. процессы, чтобы снять нагрузку на многострадальный DOM — это все детали реализации. Отсюда и vdom.

                                                                                                                                                                  Так в первом ангуляре тоже были аттрибут-селекторы, несмотря на наличие replace.
                                                                                                                                                                  Да, но директивы можно было делать и по имени тэга, и именно replace я имел в виду.

                                                                                                                                                                  которая будет каждую секунду, например, менять background хоста: черный-красный-черный-красный
                                                                                                                                                                  <Component blink/>
                                                                                                                                                                  Вы не правильно используете синтаксис — интерфейс компонента не объявляет аттрибут blink. Еще раз вернемся к jsx !== html — это более высокий уровень абстракции. Я могу вам на лету собрать мигающий компонент из немигающего — это будет правильно, и по сути тоже самое. Синтаксис другой только. Но это вам не лишняя обертка в DOM, так что все честно.
                                                                                                                                                                  const Component = ({backgroundColor, children}) => (
                                                                                                                                                                      <div style={{backgroundColor: backgroundColor}}>{children}</div>
                                                                                                                                                                  );
                                                                                                                                                                  
                                                                                                                                                                  const WithBlink = ({initialColor = 'black'} = {}) => Target => {
                                                                                                                                                                      return class Blinking extends React.Component {
                                                                                                                                                                          static displayName = `Blinking(${Target.name})`;
                                                                                                                                                                  
                                                                                                                                                                          state = {
                                                                                                                                                                              color: initialColor
                                                                                                                                                                          };
                                                                                                                                                                          interval;
                                                                                                                                                                  
                                                                                                                                                                          render() {
                                                                                                                                                                              return (
                                                                                                                                                                                  <Target backgroundColor={this.state.color} {...this.props}/>
                                                                                                                                                                              );
                                                                                                                                                                          }
                                                                                                                                                                  
                                                                                                                                                                          componentDidMount() {
                                                                                                                                                                              this.interval = setInterval(() => {
                                                                                                                                                                                  this.setState({
                                                                                                                                                                                      color: this.state.color === initialColor ? 'red' : initialColor
                                                                                                                                                                                  });
                                                                                                                                                                              }, 1000);
                                                                                                                                                                          }
                                                                                                                                                                  
                                                                                                                                                                          componentWillUnmount() {
                                                                                                                                                                              clearInterval(this.interval);
                                                                                                                                                                          }
                                                                                                                                                                      }
                                                                                                                                                                  }
                                                                                                                                                                  
                                                                                                                                                                  //static
                                                                                                                                                                  const AlreadyBlinkingComponent = WithBlink()(Component);
                                                                                                                                                                  
                                                                                                                                                                  //dynamic
                                                                                                                                                                  const render = ({backgroundColor = 'green'}) => {
                                                                                                                                                                      //on the fly
                                                                                                                                                                      const DynamicBlinkingComponent = WithBlink({initialColor: backgroundColor})(Component);
                                                                                                                                                                  
                                                                                                                                                                      //some markup
                                                                                                                                                                      return (
                                                                                                                                                                          <div>
                                                                                                                                                                              <DynamicBlinkingComponent>1</DynamicBlinkingComponent>
                                                                                                                                                                              <AlreadyBlinkingComponent>2</AlreadyBlinkingComponent>
                                                                                                                                                                          </div>
                                                                                                                                                                      );
                                                                                                                                                                  };
                                                                                                                                                                  


                                                                                                                                                                  • –1
                                                                                                                                                                    <Target backgroundColor={this.state.color} {...this.props}/>

                                                                                                                                                                    Кстати, я такую запись так и не смог нормально типизировать на TS. Как вы это разруливаете?
                                                                                                                                                                    • 0
                                                                                                                                                                      Как вы это разруливаете?
                                                                                                                                                                      В целом как-то так:
                                                                                                                                                                      import * as React from 'react';
                                                                                                                                                                      
                                                                                                                                                                      type TComponentCtr<P, S> = {
                                                                                                                                                                          new (props?: P, context?: any): React.Component<P, S>
                                                                                                                                                                      };
                                                                                                                                                                      type TResult<P, S> = React.ComponentClass<P> & TComponentCtr<P, S>;
                                                                                                                                                                      
                                                                                                                                                                      function WithBlink() {
                                                                                                                                                                          return function decorate<P>(Target: React.ComponentClass<P> | React.SFC<P>): React.ComponentClass<P> {
                                                                                                                                                                              return class Blinking extends React.Component<P, never> {
                                                                                                                                                                                  render() {
                                                                                                                                                                                      return (
                                                                                                                                                                                          <Target {...this.props}/>
                                                                                                                                                                                      );
                                                                                                                                                                                  }
                                                                                                                                                                              };
                                                                                                                                                                          };
                                                                                                                                                                      }
                                                                                                                                                                      
                                                                                                                                                                      //
                                                                                                                                                                      
                                                                                                                                                                      type TInjectedProps = {
                                                                                                                                                                          backgroundColor: string
                                                                                                                                                                      };
                                                                                                                                                                      
                                                                                                                                                                      type TOwnProps = {
                                                                                                                                                                          something: string
                                                                                                                                                                      };
                                                                                                                                                                      
                                                                                                                                                                      type TFullProps = TOwnProps & TInjectedProps;
                                                                                                                                                                      type TProps = TOwnProps & Partial<TInjectedProps>;
                                                                                                                                                                      
                                                                                                                                                                      const Component: React.SFC<TFullProps> = props => (
                                                                                                                                                                          <div>{props.something} {props.backgroundColor}</div>
                                                                                                                                                                      );
                                                                                                                                                                      
                                                                                                                                                                      //this is important! though it's not a cast (as)
                                                                                                                                                                      const Blinking: React.ComponentClass<TProps> = WithBlink()(Component);
                                                                                                                                                                      
                                                                                                                                                                      const test = <Component/>; //both props are missing
                                                                                                                                                                      const test2 = <Blinking/>; //only somthing is missing
                                                                                                                                                                      

                                                                                                                                                                      Согласен, возни супермного, но rest types на подходе: #13470, #12215, #4183, ну и ultimate #13251. Что из этого появится быстрее, остается только гадать, но типизировать HOC станет в разы проще.
                                                                                                                                                                      • 0
                                                                                                                                                                        Дааамс. Пока легче руками развернуть)
                                                                                                                                                                        • 0
                                                                                                                                                                          Ну кстати ни TComponentCtr, ни TResult не нужны…
                                                                                                                                                                          Когда введут rest types, можно будет делать как-то так:
                                                                                                                                                                          import * as React from 'react';
                                                                                                                                                                          
                                                                                                                                                                          type TTarget<P> = React.ComponentClass<P> | React.SFC<P>;
                                                                                                                                                                          type TBlinkingProps = {
                                                                                                                                                                              backgroundColor: string
                                                                                                                                                                          };
                                                                                                                                                                          function WithBlink() {
                                                                                                                                                                              return function decorate<P extends TBlinkingProps, R extends Rest<P, TBlinkingProps> & Partial<TBlinkingProps>>(Target: TTarget<P>): React.ComponentClass<R> {
                                                                                                                                                                                  return class Blinking extends React.Component<R, never> {
                                                                                                                                                                                      render() {
                                                                                                                                                                                          return (
                                                                                                                                                                                              <Target backgroundColor="red" {...this.props}/>
                                                                                                                                                                                          );
                                                                                                                                                                                      }
                                                                                                                                                                                  };
                                                                                                                                                                              };
                                                                                                                                                                          }
                                                                                                                                                                          
                                                                                                                                                                          //
                                                                                                                                                                          
                                                                                                                                                                          type TProps = TBlinkingProps & {
                                                                                                                                                                              something: string
                                                                                                                                                                          };
                                                                                                                                                                          
                                                                                                                                                                          const Component: React.SFC<TProps> = props => (
                                                                                                                                                                              <div>{props.something} {props.backgroundColor}</div>
                                                                                                                                                                          );
                                                                                                                                                                          
                                                                                                                                                                          const Blinking = WithBlink()(Component);
                                                                                                                                                                          
                                                                                                                                                                          const test = <Component/>; //both props are missing
                                                                                                                                                                          const test2 = <Blinking/>; //only somthing is missing
                                                                                                                                                                          
                                                                                                                                                                    • 0
                                                                                                                                                                      > Ну подкиньте хоть пример, что вам накатать. А то я придумать не могу, у меня в компонентах бизнес-логика не сидит как-то.

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

                                                                                                                                                                      > Вы до сих пор живете внутри html-шаблона, тогда как jsx !== html.

                                                                                                                                                                      Слушайте, ну на эту маркетинговую чепуху ведутся только те, кто на php ни разу не писал. Называть-то вы это можете как угодно, но суть явления от смены нвзвания не меняется, и jsx выглядит в точности как генерация портянок html коды из пыха, то самое прокидывание пропсов кстати — оно и в php было, там же тоже функциями генерили, render-методы у классов :)

                                                                                                                                                                      > Принцип этот не оттуда

                                                                                                                                                                      Именно оттуда :)
                                                                                                                                                                      Это сделано для того, чтобы логика клиент-сайда максимально напоминала логику сервер-сайда. Именно сервер-сайд у вас работает по принципы state -> view. Ну а вдом — да, деталь реализации, необходимая для того, чтобы «писать на клиенте как на сервере».

                                                                                                                                                                      > Да, но директивы можно было делать и по имени тэга, и именно replace я имел в виду.

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

                                                                                                                                                                      > Вы не правильно используете синтаксис — интерфейс компонента не объявляет аттрибут blink.

                                                                                                                                                                      Я ж вам показываю ангуляроподобный синтаксис. А задача — сделать как в ангуляре, все верно.

                                                                                                                                                                      > Еще раз вернемся к jsx !== html — это более высокий уровень абстракции.

                                                                                                                                                                      Да наоборот все. Шаблоны — это ДСЛ, а в jsx вы пишете по факту на хост-языке.

                                                                                                                                                                      > Я могу вам на лету собрать мигающий компонент из немигающего — это будет правильно, и по сути тоже самое. Синтаксис другой только.

                                                                                                                                                                      Ну хорошо, пусть другой. Но объявлять отдельно блинкающуюся компоненту я не хочу, я хочу сразу в jsxe как-то это сделать. Как будет ваш код без объявления промежуточного AlreadyBlinkingComponent выглядеть? Что если у меня таких директив не одна, а 10? мне 2^10=1024 таких компонент объявлять? Кроме того, ваша компонента изначально позволяет менять background-color, то есть заточена работать с blinked. Я хочу возможность работы с любой компонентной, даже с той, у которой background-color в пропсах нет.
                                                                                                                                                                      • –1
                                                                                                                                                                        Ну так а я о чем? Не сидит. Вот вы и покажите мне реальный пример, где бизнес-логика в компонентах не сидит, а не кнопки--однострочники :)
                                                                                                                                                                        Как мне вам показать пример компонента с бизнес-логикой, которая в нем не сидит? Компонент — state => ui, вся бизнес-логика в сагах, все состояние в редьюсерах.

                                                                                                                                                                        Слушайте, ну на эту маркетинговую чепуху ведутся только те, кто на php ни разу не писал.
                                                                                                                                                                        Все понятно

                                                                                                                                                                        Называть-то вы это можете как угодно, но суть явления от смены нвзвания не меняется, и jsx выглядит в точности как генерация портянок html коды из пыха, то самое прокидывание пропсов кстати — оно и в php было, там же тоже функциями генерили, render-методы у классов :)
                                                                                                                                                                        Надеюсь, что вы когда-нибудь дойдет до осознания, что jsx — это не разметка страницы, а формальный язык описания интерфейса. А то, что есть выхлоп в html — так это один из возможных вариантов.

                                                                                                                                                                        В первом ангуляре было и то и то.
                                                                                                                                                                        В первом ангуляре были только директивы. Которые «выглядели» как компоненты. С сохранением нужной гибкости: не нужна обертка — ставим replace.

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

                                                                                                                                                                        Да наоборот все. Шаблоны — это ДСЛ, а в jsx вы пишете по факту на хост-языке.
                                                                                                                                                                        jsx — это не какой-то шаблон, который «живет отдельно от модели», это описание композиции функций — посмотрите выхлоп бабеля в конце концов уже.

                                                                                                                                                                        я хочу сразу в jsxe как-то это сделать
                                                                                                                                                                        я тоже много чего хочу

                                                                                                                                                                        Как будет ваш код без объявления промежуточного AlreadyBlinkingComponent выглядеть?
                                                                                                                                                                        Я вроде показал — создание Dynamic на лету.

                                                                                                                                                                        Что если у меня таких директив не одна, а 10? мне 2^10=1024 таких компонент объявлять?
                                                                                                                                                                        Перечитал раза 3 — не понимаю о чем вы. То, что в рантайме создается что-то? Ну так у вас AlreadyBlinking позволяет принимать тот же пропс. Используйте его.

                                                                                                                                                                        Я хочу возможность работы с любой компонентной, даже с той, у которой background-color в пропсах нет.
                                                                                                                                                                        Пффф, и как вы это в директиве сделаете? Либо через @Host с простановкой нужного инпута (а это ровно тот же случай) либо через nativeElement — а это прямой доступ в DOM.

                                                                                                                                                                        Вы ерунду-то не несите, очевидно же, что задача решена, а вам обидно.

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

                                                                                                                                                                          Ну так в том и дело. Я хочу увидеть, как будет выглядеть ваше решение в полноценном виде, с отдельной моделью.

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

                                                                                                                                                                          Ну так и HTML — это формальный язык описания интерфейса.

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

                                                                                                                                                                          Так наследованием — все работает. Но вам это не нравится по синтаксическим соображениям.

                                                                                                                                                                          > В первом ангуляре были только директивы. Которые «выглядели» как компоненты. С сохранением нужной гибкости: не нужна обертка — ставим replace.

                                                                                                                                                                          Еще раз — вы говорите что раз есть реплейс, то атрибут-директивы не нужны. Но они там были. Почему?

                                                                                                                                                                          > jsx — это не какой-то шаблон, который «живет отдельно от модели», это описание композиции функций — посмотрите выхлоп бабеля в конце концов уже.

                                                                                                                                                                          Шаблоны ангуляра — это тоже описание композиции функций. Они компилируются так же как jsx в чистый джаваскрипт, там хтмля не остается. Ну и на пехепе тоже композиции функций писали :)

                                                                                                                                                                          > Я вроде показал — создание Dynamic на лету.

                                                                                                                                                                          Ну вы же создаете ее все равно в промежуточном виде. Как сразу в jsx? Или он превратился в тыкву тут?

                                                                                                                                                                          > Вы ерунду-то не несите, очевидно же, что задача решена, а вам обидно.

                                                                                                                                                                          Нет, не решена. Сделайте, чтобы работало с любой компонентной.

                                                                                                                                                                          > А еще лучше — приведите конкретный пример для переноса на реакт.
                                                                                                                                                                          @Directive({
                                                                                                                                                                              selector: "[mixin]",
                                                                                                                                                                          })
                                                                                                                                                                          export class MixinDirective implements OnDestroy  {
                                                                                                                                                                              @HostBinding("style.backgroundColor") color = "red";
                                                                                                                                                                          
                                                                                                                                                                              subscription = Observable.interval(1000)
                                                                                                                                                                                  .subscribe(x => this.color = this.color === "red" ? "black" : "red");
                                                                                                                                                                          
                                                                                                                                                                              ngOnDestroy = () => this.subscription.unsubscribe();
                                                                                                                                                                          }
                                                                                                                                                                          

                                                                                                                                                                          • 0
                                                                                                                                                                            Ну так в том и дело. Я хочу увидеть, как будет выглядеть ваше решение в полноценном виде, с отдельной моделью.
                                                                                                                                                                            Мне вам что, сюда проект скопипастить? Будет выглядеть как в любом примере с сагами. Ну и вы так и не сказали, решение чего.

                                                                                                                                                                            Еще раз — вы говорите что раз есть реплейс, то атрибут-директивы не нужны. Но они там были. Почему?
                                                                                                                                                                            Потому что тогда не было концепции компонентов. Были только html-тэги и всевозможные аттрибуты на них. Что, к слову, яростно нарушалось ангуляром, так как по спеке доспускались аттрибуты через data- а не все подряд. Это безобразие и перекочевало в головы пхп-шников, пришедших в первый ангуляр. Ну а дальше вы знаете.

                                                                                                                                                                            Шаблоны ангуляра — это тоже описание композиции функций.
                                                                                                                                                                            Прекрасно. Только компоузятся они хуже. Там где ангуляр не вытаскивает, вы пытаетесь решить задачу наследованием. А мы помним про composition over inhertitance.

                                                                                                                                                                            Ну вы же создаете ее все равно в промежуточном виде. Как сразу в jsx? Или он превратился в тыкву тут?
                                                                                                                                                                            Вы можете себе представить что-то такое:
                                                                                                                                                                            function f(a: any, b: any, c:any): void {
                                                                                                                                                                            }
                                                                                                                                                                            
                                                                                                                                                                            f(1, 2, 3, blink);
                                                                                                                                                                            
                                                                                                                                                                            «Промежуточный» вид ничем от вашей хотелки не отличается, так как и то, и то все-равно находится внутри одного скоупа функции рендер. Вы просто живете html-аттрибутами, тогда как компонент не является html-тэгом. У него есть строго описанный интерфейс. В случае с TS, например, вам даже лишний проп запихнуть в компонент не дадут без явного объявления в его интерфейсе.

                                                                                                                                                                            Нет, не решена. Сделайте, чтобы работало с любой компонентной.
                                                                                                                                                                            Пффф, и как вы это в директиве сделаете? Либо через Host с простановкой нужного инпута (а это ровно тот же случай) либо через nativeElement — а это прямой доступ в DOM.
                                                                                                                                                                            Вы ерунду-то не несите, очевидно же, что задача решена, а вам обидно.


                                                                                                                                                                            @HostBinding(«style.backgroundColor») color = «red»;
                                                                                                                                                                            :lol: то, что вы это в строку запихнули — не значит, что HostBinding в DOM не лезет. Тогда я не понимаю, чем вам не нравится ref/findDOMNode. Ну и вы нарушаете инкапсуляцию компонента, подразумевая что он имеет интерфейс DOM-ноды. И выглядит это как monkey-patching. А почему? А потому что ангуляр застрял в html-шаблоне.

                                                                                                                                                                            • 0
                                                                                                                                                                              > Мне вам что, сюда проект скопипастить?

                                                                                                                                                                              Зачем проект? Просто пример.

                                                                                                                                                                              > Ну и вы так и не сказали, решение чего.

                                                                                                                                                                              Так пусть будет с теми же кнопками. Просто структурировано так, как это будет в реальности, на нормальных компонентах, с выделенной моделью.

                                                                                                                                                                              > Это безобразие и перекочевало в головы пхп-шников, пришедших в первый ангуляр

                                                                                                                                                                              Вот в ангуляре как раз в отличии от реакта от пхп ничего не было :)
                                                                                                                                                                              То же двухсторонний биндинг — сугубо антипхпшная концепция.

                                                                                                                                                                              > А мы помним про composition over inhertitance.

                                                                                                                                                                              В этой имеется ввиду фразе не та композиция, которая функциональная.

                                                                                                                                                                              > Вы можете себе представить что-то такое:

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

                                                                                                                                                                              > Тогда я не понимаю, чем вам не нравится ref/findDOMNode.

                                                                                                                                                                              Ну хорошо, пусть будет с рефом. Главное, чтобы работало.
                                                                                                                                                                              • 0
                                                                                                                                                                                Просто пример.
                                                                                                                                                                                Какой пример? Как передать в компонент «модель»? Ну держите:
                                                                                                                                                                                type TModel = {
                                                                                                                                                                                	name: Observable<string>
                                                                                                                                                                                };
                                                                                                                                                                                
                                                                                                                                                                                type TProps = {
                                                                                                                                                                                	model: TModel
                                                                                                                                                                                };
                                                                                                                                                                                
                                                                                                                                                                                type TState = {
                                                                                                                                                                                	name: string
                                                                                                                                                                                };
                                                                                                                                                                                
                                                                                                                                                                                class Person extends React.Component<TProps, TState> {
                                                                                                                                                                                	private unsubscribe = new Subject<never>();
                                                                                                                                                                                
                                                                                                                                                                                	componentWillMount() {
                                                                                                                                                                                		this.props.model.name.takeUntil(this.unsubscribe).subscribe(name => {
                                                                                                                                                                                			this.setState({
                                                                                                                                                                                				name
                                                                                                                                                                                			});
                                                                                                                                                                                		});
                                                                                                                                                                                	}
                                                                                                                                                                                
                                                                                                                                                                                	componentWillUnmount() {
                                                                                                                                                                                		this.unsubscribe.next();
                                                                                                                                                                                		this.unsubscribe.complete();
                                                                                                                                                                                	}
                                                                                                                                                                                
                                                                                                                                                                                	render() {
                                                                                                                                                                                		const {name} = this.state;
                                                                                                                                                                                		return (
                                                                                                                                                                                			<div>Hi, {name}</div>
                                                                                                                                                                                		);
                                                                                                                                                                                	}
                                                                                                                                                                                }
                                                                                                                                                                                
                                                                                                                                                                                Но вы же понимаете, что это антипаттерн в случае реакта?
                                                                                                                                                                                Смотрите, я трюк покажу, как элегантно выпилить возможную логику из компонента:
                                                                                                                                                                                // Model.ts
                                                                                                                                                                                type TModel = {
                                                                                                                                                                                	color: string
                                                                                                                                                                                };
                                                                                                                                                                                
                                                                                                                                                                                export const create = (): TModel => ({
                                                                                                                                                                                	color: 'black'
                                                                                                                                                                                });
                                                                                                                                                                                
                                                                                                                                                                                export const changeColor = (model: TModel): TModel => ({
                                                                                                                                                                                	color: model.color === 'black' ? 'red' : 'black'
                                                                                                                                                                                });
                                                                                                                                                                                
                                                                                                                                                                                // Component.ts
                                                                                                                                                                                import * as Model from './Model.ts'
                                                                                                                                                                                
                                                                                                                                                                                export class Component extends React.Component<never, TModel> {
                                                                                                                                                                                	state: TModel = Model.create();
                                                                                                                                                                                		
                                                                                                                                                                                	render() {
                                                                                                                                                                                		const style = {
                                                                                                                                                                                			backgroundColor: this.state.color
                                                                                                                                                                                		};
                                                                                                                                                                                		
                                                                                                                                                                                		return (
                                                                                                                                                                                			<div style={style}>
                                                                                                                                                                                				<button onClick={this.onClick}>change</button>
                                                                                                                                                                                			</div>	
                                                                                                                                                                                		);
                                                                                                                                                                                	}
                                                                                                                                                                                	
                                                                                                                                                                                	onClick = () => {
                                                                                                                                                                                		this.setState(Model.changeColor);
                                                                                                                                                                                	}
                                                                                                                                                                                }
                                                                                                                                                                                

                                                                                                                                                                                И тестируете вы отдельно взятые функции create и changeColor — проще простого, без окружения и без моков.
                                                                                                                                                                                Просто структурировано так, как это будет в реальности, на нормальных компонентах, с выделенной моделью
                                                                                                                                                                                В реальности этой «модели» вообще не будет — кнопка это props => ui, какая модель? Props — вот ваша модель, просто без стейта. Если у вас в компонентах сидят какие-то сложные выделенные сущности со сложным стейтом — вы что-то делаете не так.

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

                                                                                                                                                                                В этой имеется ввиду фразе не та композиция, которая функциональная
                                                                                                                                                                                Я аж поперхнулся. Естественно я вам не про функциональную композицию.

                                                                                                                                                                                Вот хороший пример. В случае с ф-и я могу ф-ю прямо в коде использовать, без промежуточного объявления.
                                                                                                                                                                                Что, простите? Поясните

                                                                                                                                                                                Ну хорошо, пусть будет с рефом. Главное, чтобы работало.

                                                                                                                                                                                const WithBlink = ({initialColor = 'black'} = {}) => Target => {
                                                                                                                                                                                    return class Blinking extends React.Component {
                                                                                                                                                                                        static displayName = `Blinking(${Target.name})`;
                                                                                                                                                                                
                                                                                                                                                                                        color: initialColor;
                                                                                                                                                                                        interval;
                                                                                                                                                                                
                                                                                                                                                                                        render() {
                                                                                                                                                                                            return (
                                                                                                                                                                                                <Target {...this.props}/>
                                                                                                                                                                                            );
                                                                                                                                                                                        }
                                                                                                                                                                                
                                                                                                                                                                                        componentDidMount() {
                                                                                                                                                                                            this.interval = setInterval(() => {
                                                                                                                                                                                                this.color = this.color === initialColor ? 'red' : initialColor;
                                                                                                                                                                                                findDOMNode(this).style.backgroundColor = this.color;
                                                                                                                                                                                            }, 1000);
                                                                                                                                                                                        }
                                                                                                                                                                                
                                                                                                                                                                                        componentWillUnmount() {
                                                                                                                                                                                            clearInterval(this.interval);
                                                                                                                                                                                        }
                                                                                                                                                                                    }
                                                                                                                                                                                }
                                                                                                                                                                                
                                                                                                                                                                                Как-то даже без рефа вышло.
                                                                                                                                                                                • 0
                                                                                                                                                                                  > Как передать в компонент «модель»?

                                                                                                                                                                                  Вы у меня спрашиваете?

                                                                                                                                                                                  > В реальности этой «модели» вообще не будет — кнопка это props => ui, какая модель? Props — вот ваша модель, просто без стейта.

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

                                                                                                                                                                                  > вы что-то делаете не так.

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

                                                                                                                                                                                  > Лихо вы байндингами прикрылись. То, что в реакте их нет, а в ангуляре есть, не делает из первого пхп, а из второго нет.

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

                                                                                                                                                                                  > Что, простите? Поясните

                                                                                                                                                                                  У меня есть функция f и фвп g, тогда я могу применить вторую к первой и сразу вызвать в коде своем: let x = g(f)(arg). Мне не требуется сперва класть перед этим новую ф-ю в отдельную переменную, вот так: let f2 = g(f), let x = f2(arg);
                                                                                                                                                                                  В jsx — приходится.

                                                                                                                                                                                  > Как-то даже без рефа вышло.

                                                                                                                                                                                  Отлично. И внезапно выясняется, что с functional component ваш HOC работать не будет. Таким образом, гипотеза о том, что все ваши красивые однострочники выше в реальности неприменимы — доказана. Ну и этот вариант явно проигрывает оригиналу на ангуляре. Причем проигрывает, как мне кажется, значительнее, чем проигрывал ангуляр на вашей задаче.
                                                                                                                                                                                  • 0
                                                                                                                                                                                    Вы у меня спрашиваете?
                                                                                                                                                                                    Не паясничайте.
                                                                                                                                                                                    В реальности как раз такого обычно не бывает. Реальные компоненты содержат локальный стейт, который в общем часто довольно-таки нетривиально должен обрабатываться.
                                                                                                                                                                                    В реальности как-раз стейт минимизируется. Либо изолируется, как я показал вам в примере с трюком. Который вы так элегантно проигнорировали.

                                                                                                                                                                                    Но когда у вас действительно серьезная логика, то в первом случае — получится просто туча пропсов, до уровня неюзабельности, а во втором — ну вы охренеете делать это через редакс, даже с сагами, поддерживать эту мешанину будет невозможно.
                                                                                                                                                                                    Давайте пример серьезной логики, сидящей в UI-слое! Вы же вроде за архитектуру? Что у вас серьезная логика в UI делает?

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

                                                                                                                                                                                    У меня есть функция f и фвп g, тогда я могу применить вторую к первой и сразу вызвать в коде своем: let x = g(f)(arg). Мне не требуется сперва класть перед этим новую ф-ю в отдельную переменную, вот так: let f2 = g(f), let x = f2(arg);
                                                                                                                                                                                    В jsx — приходится.
                                                                                                                                                                                    А, так вот вы о чем. Тут соглашусь, но я не зря написал где-то выше по поводу сожалений о том, что взяли xml-подобный синтаксис, который сам по себе такие вещи не умеет. Как, собственно, любой движок с таким синтаксисом (взять тот же XAML). Ну и, к слову, вы в ангуляре вообще на лету ничего не можете сделать. JSX хотя бы через доп. декларацию позволяет такую динамику.

                                                                                                                                                                                    И внезапно выясняется, что с functional component ваш HOC работать не будет.
                                                                                                                                                                                    C чего вы взяли? Target прекрасно может быть SFC. Более того, я просто не включил в этот пример окружение из прошлого (без findDOMNode) — оно точно такое же. findDOMNode(this) получает дом-ноду на которой замаунчен текущий компонент, даже если он рендерит другой, дом-нода то одна на всех. В этом и прелесть (отсутствие обертки).
                                                                                                                                                                                    • 0
                                                                                                                                                                                      > Либо изолируется, как я показал вам в примере с трюком.

                                                                                                                                                                                      Этот трюк только на чистых ф-х работает, что будет, если надо заапдейтить стейт асинхронно?

                                                                                                                                                                                      > Что у вас серьезная логика в UI делает?

                                                                                                                                                                                      Управляет UI.
                                                                                                                                                                                      Представьте себе, не всем повезло работать с примитивными интерфейсами вроде твиттера :)
                                                                                                                                                                                      Ангуляр вообще больше предназначен для корпоративного сегмента.

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

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

                                                                                                                                                                                      > C чего вы взяли?

                                                                                                                                                                                      Да, действительно, this ссылается на полноценную компоненту. Но в любом случае, это не будет работать с ref, так что либо всей команде придется запретить использовать ref, либо функциональные директивы. Поболее предпочтительный вариант кажется очевидным.

                                                                                                                                                                                      > В этом и прелесть (отсутствие обертки).

                                                                                                                                                                                      Еще раз напоминаю, что вариант с наследованием в ангуляре тоже не дает обертки.
                                                                                                                                                                                      • 0
                                                                                                                                                                                        Этот трюк только на чистых ф-х работает, что будет, если надо заапдейтить стейт асинхронно?
                                                                                                                                                                                        Ну так в этом и смысл, что все операции над стейтом чистые и тестируемые. Всмысле асинхронно? Ну вызовите setState с этой функцией «асинхронно», в чем проблема?

                                                                                                                                                                                        Управляет UI.
                                                                                                                                                                                        Что ж она там так делает сосредоточенно? Ну пример давайте уже.

                                                                                                                                                                                        Представьте себе, не всем повезло работать с примитивными интерфейсами вроде твиттера :)
                                                                                                                                                                                        Я смотрю у вас там серьезно все, космолеты пилите, может поделитесь проектом?

                                                                                                                                                                                        Ангуляр вообще больше предназначен для корпоративного сегмента.
                                                                                                                                                                                        Это маркетинговый булшит, сверкающая сказка, заливаемая в уши менеджерам. Из-за этой легенды и появляются заказчики, слепо верящие в «корпоративность», «энтерпрайзность» и прочую лабуду. А разработка потом страдает, копаясь в этом недоделанном болоте, попутно вставляя костыли в поломанных после очередного обновления местах и штурмуя гитхаб в поисках тикета на баг. Корпоративный сегмент, бред какой.

                                                                                                                                                                                        Но в любом случае, это не будет работать с ref
                                                                                                                                                                                        И что? Оно и не должно

                                                                                                                                                                                        так что либо всей команде придется запретить использовать ref, либо функциональные директивы
                                                                                                                                                                                        Вы поймите, не работает не потому, что это бага или кривой дизайн, не работает потому, что у SFC нет инстанса — это функция props => ui. А если нет инстанса, нет и ссылки на него. Это же очевидно.

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

                                                                                                                                                                                        Еще раз напоминаю, что вариант с наследованием в ангуляре тоже не дает обертки.
                                                                                                                                                                                        Еще раз напоминаю, что в этом варианте слишком много костылей.
                                                                                                                                                                                        • 0
                                                                                                                                                                                          > Ну вызовите setState с этой функцией «асинхронно», в чем проблема?

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

                                                                                                                                                                                          > Что ж она там так делает сосредоточенно? Ну пример давайте уже.

                                                                                                                                                                                          Собирает динамические многоэтажные формы, например.

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

                                                                                                                                                                                          Это ваше мнение, но факт остается фактом :)

                                                                                                                                                                                          > Именно — запретить использовать ref.

                                                                                                                                                                                          И использовать вместо него findDOMNode, который не рекомендован? Серьезно?

                                                                                                                                                                                          > В остальном — почти всегда можно пойти декларативным путем.

                                                                                                                                                                                          Ну вот задача — сделать blink-компоненту которую можно применить на любую другую (то есть без дополнительных пропсов). Она решается либо через реф (рекомендованный путь), либо через findDOMNode (не рекомендованный путь). Вы сейчас на полном серьезе предлагаете отказаться от рекомендованного варианта, ради чего? Чтобы сэкономить на спичках три строки при определении функциональных компонент?
                                                                                                                                                                                          • 0
                                                                                                                                                                                            Или заресолвить этот промис внутри компоненты и в then обновить стейт? Тогда у вас по сути часть логики подгрузки данных протекает в компоненту, о какой изоляции речь?
                                                                                                                                                                                            Простите, а что не так в setState из then? Вы хотите из ui-библиотеки сделать движок с автоматическим связыванием. Вот так нельзя. Стейт компонента нужен для синхронного изменения ui, все остальное вы можете использовать как угодно, через промисы, через стримы, через что угодно. Только если вам нужно изменить ui — вы это делаете через setState с нужными вам данными, например, в том же контейнере. Вы просто от реакта слишком многого хотите.

                                                                                                                                                                                            Собирает динамические многоэтажные формы, например.
                                                                                                                                                                                            Подозреваю, что там нет асинхронщины и нет стейта, а такая логика отлично выносится из компонента в модуль. Вообще, мне кажется, что такие вещи на реакте удобнее делать: form-configuration => ui — вот и весь компонент ConfigurableForm.

                                                                                                                                                                                            findDOMNode
                                                                                                                                                                                            Ну так там и сказано, что можно использовать, когда нужны всякие DOM measurements. Вы getBoundingClientRect без nativeElement в ангуляре тоже не вызовете. К слову, ref тоже не рекомендуется использовать.

                                                                                                                                                                                            Ну вот задача — сделать blink-компоненту которую можно применить на любую другую (то есть без дополнительных пропсов).
                                                                                                                                                                                            Я все-равно буду решать эту задачу через интерфейс. Еще и запрещу вызывать HOC на компонентах без backgroundColor пропса — это правильный декларативный путь, а патчить DOM-ноду чужого компонента — хак, нарушающий декларативность и абстракцию компонента.
                                                                                                                                                                                            type TBlinkingProps = {
                                                                                                                                                                                              backgroundColor: string
                                                                                                                                                                                            };
                                                                                                                                                                                            type TTarget = React.ComponentClass<TBlinkingProps> | React.SFC<TBlinkingProps>;
                                                                                                                                                                                            const WithBlink = () => (Target: /* constraint! */ TTarget) => ...
                                                                                                                                                                                            


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