JSX: антипаттерн или нет?

    Довольно часто приходится слышать, что React и особенно JSX-шаблоны – это плохо, и хороший разработчик так не делает. Однако нечасто объясняется, чем именно вредит смешивание верстки и шаблонов в одном файле. И с этим мы попробуем сегодня разобраться.


    Подход "каждой технологии свой файл" использовался с начала существования веба, поэтому неудивительно, что слом этого шаблона вызывает отторжение некоторых разработчиков. Но перед тем, как заявлять "нет, мы так делать не будем никогда", будет полезно разобраться истории и понять, почему JSX пользоваться можно, а смешивать скрипты и html – нет.



    История


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


    Однако по мере усложнения сайтов появилась необходимость переиспользовать стили и скрипты на разных страницах. Со временем подход "CSS и JS отдельно от HTML" стал общей рекомендацией. Особенно при условии, когда HTML генерируется серверным движком, в отличие от CSS и JS файлов, которые меняются только при разработке и отдаются сервером как есть. Разделение контента на статический и динамический позволяет пользователю загружать меньше данных, за счет кеширования, а разработчику удобнее редактировать статические файлы, а не искать куски Javascript в шаблонах используемой CMS.


    Со временем стало появляться все больше одностраничных веб-приложений, где основная часть логики сосредоточена на клиентской стороне. На любой URL сервер отдает один и тот же статичный HTML, а Javascript код в браузере пользователя определяет текущий адрес и делает запрос на сервер за нужными данными. При клике на ссылку, страница не перезагружается целиком, а лишь обновляется URL, а Javascript-код делает новый запрос для следующей страницы.


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


    Наиболее подходящим способом организации такой массы кода стал компонентный подход. Каждый более или менее независимый блок оформляется в отдельный компонент, со своими стилями, шаблоном и Javascript, а потом из этих блоков собирается страница целиком.


    Этот подход реализуется большинством современных JS-фреймворков, но с одним отличием: Angular, Ember и Marionette поощряют создание отдельного файла с шаблоном, а React предлагает писать HTML внутри JS. И это становится красной тряпкой для некоторых разработчиков.


    Шаблон и компонент


    А в чем смысл создания отдельного файла с шаблоном? Часто приводится довод: разделить разные сущности, потому что так правильно. Хотя исторически причиной отделения HTML и JS было разделение статики и динамики, что уже неактуально для рендеринга на клиенте


    Итак, насколько же компонент и его шаблон разные? Возьмем фрагмент кода



    Линиями показаны взаимосвязи, в которых изменение изменения одного файла затронут и другой. Если бы это была связь между двумя JS-модулями, рефакторинг напрашивается сам собой. Но для view и шаблона так не делают, потому что это неправильно.


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


    А насколько это вредит в реальному проекту? Попробуем провести эксперимент и объединить шаблон с JS:


    import Marionette from 'backbone.marionette';
    import {warningText} from '../constants';
    
    export default Marionette.ItemView.extend({
      template(templateData) {
        const {title, img_url, count} = templateData;
        const isSelected = this.model.isSelected();
        const isOverLimit = this.model.get('count') > this.model.get('maxAvailable')
        return `<div class="cart-item ${isSelected ? 'active' : ''}">
          <h3>${title}</h3>
          <img src="http://${img_url}" />
          <div>
            <button class="btn-less">-</button>
            <input value="${count}" />
            <button class="btn-more" ${isOverLimit ? 'disabled': ''}>+</button>
          </div>
          ${isOverLimit ? warningText : ''}
        </div>`;
      },
      events: {
        'click btn-less': 'onLessClick',
        'click btn-more': 'onMoreClick'
      }
    });

    Благодаря появлению в EcmaScript6 template strings, создание встроенных шаблонов стало приятнее. Подсветка HTML внутри строки так же настраивается. А по сравнению с прошлым примером, кода стало меньше за счет удаления прослойки, которая готовила данные в шаблон.


    Так стоит ли так делать в своих проектах с использованием не React? Скорее всего, нет, потому что они не заточены на такой стиль. Но я надеюсь, что теперь стало понятнее, что встраивание HTML в код компонента не так уж плохо и приносит пользу в некоторых случаях.

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

    Подробнее
    Реклама
    Комментарии 216
    • 0
      https://www.youtube.com/watch?v=mVVNJKv9esE&t=1220
      • 0

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


        <template>
            <img src="[[img]]">
            <p>[[text]]</p>
        </template>

        И это будет более производительно, чем манипуляции со строками.

        • +3

          в React манипуляций со строками нет. В коде компонента вы пишете


          render() {
             return <div>
               <h1>Hello!</h1>
             <div>
          }

          На этапе сборки произойдет конвертация JSX -> JS и код станет таким


          render() {
             return React.createElement('div', null, [
                   React.createElement('h1', null, 'Hello!')
             ]);
          }

          Получается обыная JS-конструкция, которая легко и быстро парсится браузером.


          А поскольку React.createElement лишь генерирует JS-объект, который легче DOM-объекта, то все будет работать быстрее, но это уже другая история про React Virtual DOM.

          • +9

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


            И это уже не говоря о том, на сколько сгенерированный React сниппет будет медленней чем простой <template>, который браузер парсит напрямую, и то, что для <template> нет необходимости в системе сборки (всегда хорошо иметь необязательные вещи, это добавляет гибкости).

            • –1
              Но ведь мы то понимаем, что на чистом ДОМ, да еще оптимально, можно написать 1-2 критичных компонента, но не все приложение.
              • +2

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


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

              • +3

                Если рассматривать сферический DOM в вакууме, то да, React == Shadow DOM + DOM, а потому медленнее.
                Но на самом деле речь ведь о скорости и сложности, с которой DOM переводится из состояния A в состояние B.
                Да, эффективное использование DOM всегда быстрее, но сложность в таком случае может расти очень быстро, если речь идёт о чем-то более сложном, чем обновление properties на узлах. И тут внезапно может оказаться, что толковый подход это уже половина реактовского dom reconciliation, только глючная и никем не тестированная.

                • +1

                  Это зависит от многих факторов: иногда и правда дико сложно, иногда совсем нет.


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


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

                • 0

                  В вашем примере template с "нативным" DOM есть конструкции "[[img]]" и "[[text]]". В других ваших примерах кода есть и посложнее: "[[isSelected, 'active', '']]".


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


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

                  • +1

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


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


                    Если соизволите сделать простой пример на React — с радостью портирую его на Polymer 1.x для сравнения.


                    На счёт сборки — да, для производительности инициализации это плюс. В теории для Polymer тоже можно реализовать систему сборки и дополнительно к <template> хранить ещё и мета-информацию о том, что находится внутри. На практике такое либо кто-то пробовал и увидел что бессмысленно, либо просто ни у кого не дошли до этого руки, вот уж не знаю что из этого.

                    • 0

                      Polymer замечательно хранит свою мета-информацию в properties, как и Peact в state. Между Polymer и React вообще вся разница, по большому счету, в том, что Polymer опирается на стандарты а React — на костыли.

                      • 0

                        Я знаком с внутренностями Poymer) Имел ввиду, что мета-информацию Polymer всё-таки при инициализации собирает, а мог бы собирать во время сборки, что позволило бы выжать ещё немного производительности.

                        • 0
                          Я знаком с внутренностями Poymer

                          это я понял, я говорю о нем именно в контексте сравнения с Реакт, о том, что после сборки проекта на Полимере vulcanize-ом никакого преимущества в плане производительности у Реакта нет: и там и там мы имеем все свойства в памяти и связывание с реальным DOM, при этом быстрее будет скорее Полимер из-за оптимизации работы браузера с веб-компонентами (пока конечно только в Хроме но скоро и в остальных браузерах).

                          • 0
                            >при этом быстрее будет скорее Полимер из-за оптимизации работы браузера с веб-компонентами (пока конечно только в Хроме но скоро и в остальных браузерах).

                            Быстрее чем простой жаваскрипт объект для компоненты в реакте?
                            • 0

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

                              • 0
                                А как вы пришли к выводу о том что нативная поддержка веб-компонентов позволит сделать какие-то оптимизации из-за которых оно будет быстрее чем использование простого жаваскрипт объекта?
                                • 0

                                  DOM — это такая громоздкая штуковина со сложной иерархией, кучей собственных подписок на события, кучей эмиторов, и главное, жесткой связью всего этого с рендером в браузере. Прослойка в виде виртуального DOM — не избавляет нас от необходимости вносить изменения в DOM реальный, а потому, некорректно просто сравнивать скорость изменений абстрактного js-объекта с итоговым рендером всей этой кухни. А вот при работе с реальным DOM уже много чего возможно сделать и далеко не только в рамках js-рантайма, вспомните хотя-бы про css свойство will-change. Поэтому, при нативной поддержке веб-компонентов возможна более глубокая оптимизация.

                                  • 0
                                    Речь не про прослойки, которые занимаются изменением DOM'а, тк спека веб-компонент всё равно не предоставляет никакого датабайндинга, сейчас мы просто говорим про компоненты и оверхэд компонент.

                                    Если вы не знали, то компоненты в реакте — это простые жаваскрипт объекты, которые не имеют никакого отношения к DOM. А вот нативные веб-компоненты — это уже громоздкие DOM объекты.
                                    • 0

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

                                      • 0
                                        >Ну конечно, реактовские компоненты в сферическом вакууме летают и никак не связаны с DOM, а в браузере отображаются исключительно магическим образом, без всякой громоздкости

                                        Реакт компоненты никак не отображаются в браузере, в браузере отображаются только DOM элементы.

                                        Реакт компоненты — это простой объект + лайфсайкл методы. А вот веб-компоненты — это жаваскрипт объект + DOM объект + не самые быстрые вызовы из js -> native + тормозные вызовы лайфсайклов native -> js.
                                        • 0
                                          Реакт компоненты никак не отображаются в браузере, в браузере отображаются только DOM элементы.

                                          Угу, DOM элементы появляются магически, их никто не создает, не инициализирует после отрисовки, и никто не дергает для обновления.

                                          • 0
                                            Компоненты в реакте могут и не создавать DOM элементы: https://facebook.github.io/react/blog/2016/07/13/mixins-considered-harmful.html#higher-order-components-explained

                                            Так же как и в полимере не все веб-компоненты будут отображаться и видны пользователям: https://elements.polymer-project.org/elements/iron-ajax
                                            • 0

                                              И? Как это вообще связано со скоростью работы с DOM?

                                              • +1
                                                «при этом быстрее будет скорее Полимер из-за оптимизации работы браузера с веб-компонентами (пока конечно только в Хроме но скоро и в остальных браузерах).»

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

                                                Я с радостью перейду на использование веб-компонент, когда они перестанут быть такими тормозными как сейчас в хроме ;)
                                                • 0

                                                  Ваша вера в то, что Реакту волшебным образом удается полностью избегать работы с реальным DOM мне кажется полным абсурдом. Когда вы примете тот факт, что это не так — вы сами придете к мысли, что говоря об оптимизации — мы говорим, прежде всего, об оптимизации работы с DOM. В любом случае, какой бы фреймворк или библиотека у нас не были "под капотом". Чистый js — работает быстро, заставить его заметно тормозить можно только специально стараясь. А говоря о работе именно с DOM — мы уже можем сравнить конкретные подходы. И в этих подходах, уверяю вас, нет никакой магии, все те-же обычные операции над нодами. Единственный способ сказать браузеру, что ваша нода чем-то серьезно отличается от других — использовать веб-компоненты, которые являются стандартом, в отличии от абстрактных, с точки зрения браузера, реакт-компонент. Все.

                                                  • 0
                                                    Вы так и не рассказываете про какие-либо оптимизации, которые возможны благодаря тому что веб-компоненты будут нативно реализованы в браузере в том виде, в котором они описаны в спеке веб-компонент по сравнению с простыми react-like компонентами :) Хоть один пример можно?
                                                    • 0

                                                      Конечно же, Реакт не может избежать работы с ДОМ. Это очевидно.
                                                      Реакт дает оптимизацию сценария интенсивного обновления ДОМ, предоставляя для этого легковесные джаваскрипт объекты, и применяя к ДОМ лишь конечный результат более или менее оптимальным образом.


                                                      Это всего лишь один из подходов, и странно видеть в нем решение всех проблем.

                                                      • 0
                                                        Ещё один :) Речь про реакт-компоненты и веб-компоненты, и какие-то мифические оптимизации веб-компонент.

                                                        Это не имеет никакого отношения к тому как реализован дата биндинг в полимере в традиционном angular1 стиле, или в реактовом с использованием виртуального дома. Вообще никакого отношения, потомучто веб-компонентам насрать на то как будут вставляться, удаляться или обновляться веб-компоненты.
                                                      • –1
                                                        i360u с ними спорить бесполезно.

                                                        Им нужны технологии, которые позволяют не думать и ни за что не отвечать. :)
                                                        Все то, что делает эта ерунда, можно реализовать с помощью дополнительной пары строчек кода, когда появились тормоза.
                                                        • 0
                                                          Разве тут кто-то спорит? Я лишь хочу узнать что это за «оптимизации работы браузера с веб-компонентами (пока конечно только в Хроме но скоро и в остальных браузерах).» Больше меня ничего не интересует :)
                                          • 0
                                            Ничего в них громоздкого нет, это те же самые JS-объекты.
                          • 0

                            Вы не можете получить ссылку на обновляемый узел в своем документе (в реальном DOM) на этапе сборки до отрисовки его браузером. Ничего тут React, к сожалению, не выигрывает, ему точно так-же приходится устанавливать связи при инициализации, как и Polymer. У них даже колбэки жизненного цикла компонентов похожие.

                          • 0
                            На самом деле, <template>, который браузер отпарсит в DOM, а мы потом размножим и удалим шаблон, будет намного медленней. Это была одна из проблем Angular 1, которую Angular 2 решает с помощью AoT компиляции шаблонов. Весь смысл Virtual DOM в том, что браузер очень медленно работает с DOM деревом, поэтому нужны костыли. http://stackoverflow.com/questions/28857074/angular-compile-is-slow-how-to-avoid
                            • 0
                              Маленькое уточнение — это когда мы работаем реально с DOM. Если у нас неприбинденный элемент или фрагмент — нет никаких тормозов, и чем это настолько отличается от виртуального DOM что появляется необходимость его вводить — лично мне непонятно.
                              • 0

                                В React все компоненты определяют метод render, который возвращает html исходя из актуального своего состояния.
                                Проблема в том, что этот метод в React вызывается на каждое изменение стейта. С одной стороны это преимущество, нам не нужно думать о том, как это изменение стейта отразится на html, у нас есть функция render.
                                Если бы render возвращал каждый раз настоящие DOM-элементы, это было бы медленно. Например, мы поменяли один class на active, а нам вернулся весь наш html.


                                Virtual-DOM является легкой прослойкой. Его объекты ничего не весят, поскольку не имеют ни размеров, ни подписчиков на события, это просто данные типа JSON. Его можно создавать много и дешево, а из него уже выяснять, что именно нам нужно обновить в реальном DOM

                                • 0
                                  Это понятно, но это ведь следствие кривизны реакта, не?

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

                                  Пишем в dom, биндим со стейтом и смотрим как броузер сам перерисовывает что надо. Какие могут быть подводные камни (без стеба, реально интересно мнение практика. Я сейчас подобную схему реализовываю, интересно мнение людей набивших шишек)
                                  • 0

                                    Ну такой вот другой подход на декларативные шаблоны.


                                    Есть подход React с созданием VDOM на каждое обновление и последующим вычислением diff.


                                    А есть подход Angular и Polymer которые завязываются на dom-ноду, парсят байндинги и пытаются слушать изменения и на них реагировать. Проблема этого подхода в том, что обслуживание DOM-ноды дорогое (не создание её в нативном API, а вся эта окружающая обвязка по разбору директив). Соответственно, чем больше нод, тем тормознее страничка.


                                    А у React на ноды не завязано ничего, ограничивающим местом является размер VDOM, а он легче и в него влазят бóльшие объемы данных. Поэтому я выбираю React.


                                    Кроме того, у React есть метод shouldComponentUpdate, который может не допустить обновление части поддерева, сделав страничку отзывчивее. Как сделать такое в Angular/Polymer, я не знаю.

                                    • 0

                                      Ангулар/Полимер и без всяких shouldComponentUpdate не будут обновлять поддерево.

                                      • 0
                                        Угу. Даже когда надо бы обновить, они не будут. Т.к. Angular следит за изменениями через shallowCompare. Как только у нас массив или объект с свойствами, здравствуй закат солнца вручную через ngDoCheck, причём её надо выполнять очень быстро, т.к. она будет вызываться при абсолютно любом событии и много раз за цикл rerender. А раз у нас всё вручную, то можно и забыть случайно обновить. Типа вот так https://github.com/primefaces/primeng/pull/986/
                                        • 0

                                          Это только во втором Ангуляре.

                                        • 0

                                          я о том, что в Angular нельзя сказать "внутри этого компонента ничего не поменялось, watchers вызывать не надо", а в React прекратить вызовы render дальше по дереву – можно

                                        • 0
                                          >А есть подход Angular и Polymer которые завязываются на dom-ноду, парсят байндинги и пытаются слушать изменения и на них реагировать.

                                          Я тут слегка про другое говорю. Вот есть у нас аттрибут или содержимое тега (текстовая нода). Мы разбираем jsx (без реакта) и видим что тут не скаляр кладется в атрибут или ноду а биндинг на стейт. (это в нативном кастомном элементе) Через Proxy вешаемся на стейт (это все в момент создания элемента) и в случае изменения объекта/переменной меняем содержимое атрибута/ноды. То есть перерисовку вешаем на броузер. Могут быть в такой схеме проседания по сравнению с реактовской моделью, как считаете? (то есть как я вижу — тут как раз никакого оверхеда в виде инфраструктуры это шаманство поддерживающей — нет, все нативненько, но реальность часто со мной не соглашается)
                        • 0

                          React компоненты — это и есть View + поведение. Как в PHP принято выносить в шаблоны View какое то поведение включающее в себя незамысловатое ветвление if, else, так собственно и здесь. За одним исключением — добавляется какая то минимальная реакция на события. Важно понимать границы где заканчивается View и начинается бизнес-логика.

                          • 0

                            Импользование template string вместо <template> элемента значит, что вы игнорируете возможности платформы, которые могут помочь вам распарсить кусок DOM заблаговременно, тем самым увеличив производительность.


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

                            Разница в 8 строк. Но если в первом случае когнитивная нагрузка при работе с файлами небольшая, то с JSX (имхо) когнитивная нагрузка сильно возрастает. К тому же, сама разница в количестве строк по большей части обусловлена самим React. К примеру, в Polymer подобное:


                            {{#if isOverLimit}}
                                {{warningText}}
                            {{/if}}

                            я решил кастомным методом if:


                            [[if(isOverLimit, warningText)]]

                            При чем я его могу таким образом использовать и для аттрибутов, и для свойств DOM элементов, сравните:


                            <div class="cart-item {{#if isSelected}}active{{/if}}">
                            <div class="cart-item ${isSelected ? 'active' : ''}">
                            <div class$="cart-item [[isSelected, 'active', '']]">
                            
                            <button class="btn-more" {{#if isOverLimit}}disabled{{/if}}>+</button>
                            <button class="btn-more" ${isOverLimit ? 'disabled': ''}>+</button>
                            <button class="btn-more" disabled="[[isOverLimit]]">+</button>

                            Синтаксис сравним по читаемости к template string, такой же краткий, и при этом в HTML формате, позволяя использовать для обработки возможности платформы.


                            А ещё можно писать не HTML, а Pug/Jade, где читаемость становится ещё лучше (нужно знать синтаксис, но мне кажется, зная CSS вам не составит труда понять что тут происходит):


                            div(class$="cart-item [[if(isSelected, 'active', '']]")
                              h3 [[title]]
                              img(src="http://[[img_url]]")
                              div
                                button.btn-less -
                                input(value="[[count]]")
                                button.btn-more(disabled="[[isOverLimit]]") +
                              | [[isOverLimit, warningText, '']]

                            Если в ход идут миксины, тогда разница становится ещё больше.


                            В итоге, мне кажется, JSX делает всё только хуже, не позволяя использовать сторонние инструменты вроде Pug/Jade и, по сути, больше решает проблемы синтаксиса самого React.

                            • +3

                              Добрый день!


                              С первым пунктом про template я соглашусь. Поэтому не стоит вставлять html в код фреймворка, который на это не заточен. Но React как раз приспособлен, и разбирает шаблоны во время сборки, превращая их в быстро работающий код.


                              Теперь давайте про конгитивную нагрузку.


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


                              [[if(isOverLimit, warningText)]]

                              создают даже большую нагрузку. Чтобы прочесть код компонента, нужно знать не только html и javascript, но и вспомогательные методы шаблонизатора. Поэтому при прочих равных я выберу решение, где от меня нужно знать только html и js, то есть React.


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

                              • –1
                                где весь html короткий

                                Любой HTML слишком длинный, чтобы его писать.


                                Поэтому при прочих равных я выберу решение, где от меня нужно знать только html и js, то есть React.

                                В React тоже есть синтаксис шаблонизатора, который надо знать, пусть его не так много, как в каком-нибудь handlebars.

                                • 0
                                  Синтаксиса шаблонизатора по сути не существует в React. Весь синтаксис есть Javascript и объекты Javascript, DOM объекты.
                                  • 0

                                    Есть некоторые вещи, которые в Jsc/react мешают — className, style={}, id, key… и невозможно использовать зарезервированные ключи (with, while, var, break), хотя их и не так часто потребуется использовать.

                                • 0

                                  Само собой, JSX продиктован тем, как устроен React, и в контексте React он может быть предпочтительнее.
                                  Опять таки согласен с коротким HTML, в этом случае может быть вполне резонно, но даже сниппет в статье как по мне уже больше оптимального, для внедрения в JS, размера.


                                  Jade сам по себе может сослужить достаточно мощным DSL, без ущерба читаемости.
                                  Вот сравните jade (379 байт) с html (2176 байт) (желательно отформатировать, чтобы увидеть масштаб преобразований).
                                  Там форма с 7 параметрами конфигурации и в Jade это легко понять. Не сложнее устроен и лежащий рядом JS файл, который использует общие с другими формами абстракции. Но HTML как раз получается достаточно объемным.


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


                                  Как бы вы решили подобную задачу в React? Элемент загружает данные из API в форму, и при сохранении отправляет те же данные с изменениями обратно.

                              • +1

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


                                И то, что это именно синтаксис, накладывает серьезные ограничения. Поддержка Dart, CoffeeScript, ClosureScript, HAML, Pug/Jade? Даже если есть компилятор, не факт, что IDE/редактор не сойдет с ума.


                                В этом отношении подход Vue.js гораздо изящнее. *.vue — опциональный формат (и не такой опциональный, как JSX, потому что писать React.createElement('div') никто в здравом уме не будет), и это просто html. Шаблоны, стили, код — все это пишется на любом языке и при необходимости (разрастание, верстальщик без специальных познаний) легко выносится в отдельные файлы.
                                При этом Vue.js умеет в Redux с вытекающими плюшками.


                                Простите, увлекся:) По существу: большие шаблоны в коде зло, маленькие иногда можно:)

                                • –3
                                  Я возьму Ваш комментарий в копилку IDE-зависимостей, в холиварах vim vs IDE помогает )
                                  • +1

                                    Я смотрел на Vue и Polymer, который использует такой же подход html-модулей. Но у меня как-то не зашло.


                                    Когда у вас на первом месте html, то и импорты зависимостей производятся в html. Но javascript-функции с логикой надо импортировать в JS. В результате у меня сложилось ощущение дискомфорта от разнородных импортов.


                                    У JS-first подхода есть свои преимущества. Например то, что стартовой точкой приложения в любом случае будет JS, поэтому логично с него начинать.

                                    • 0

                                      Странно, у меня во Vue как раз JS-first и входная точка именно JS. HTML я не импортирую. Vue отвечает только за вью, простите за каламбур, как и положено:) За Polymer не скажу.

                                      • 0

                                        С одной стороны может быть дискомфорт. С другой стороны, загружая HTML с помощью HTML импортов, а не в виде строки вы используете возможности платформы для парсинга содержимого, что очень важно с точки зрения производительности.

                                        • 0
                                          Парсинга чего? Все равно Polymer потом сам парсит эти строки чтобы вставить в них данные. Про какую производительность вы распинаетесь 10 комент подряд если не делали бенчмарков.
                                          • +1

                                            В контексте статьи я говорю о производительности <template> и других нативных интерфейсов вроде непосредственной работы с DOM (или максимально приближенной к ней).
                                            К примеру, сравнение использования <template> по сравнению со строкой для Shadow DOM: https://rawgit.com/ebidel/e9bcb6fc88b40fc26ed9e768f7d19961/raw/template_vs_innerhtml.html
                                            Можете добавить тест с императивным созданием элементов что будет ближе к React и посмотреть на результат.

                                            • +2
                                              Производительность DOM тут не главное, тут главное общая производительность (и библиотек и программиста который это все обслуживает) а разница между 55 и 99 мс не такая и страшная
                                      • +2
                                        Но JSX — это новый синтаксис. Нужна поддержка со стороны редакторов, IDE, линтеров, прочих инструментов

                                        оно прекрасно поддерживается babel-ом. С которым, в свою очередь, прекрасно умеет общаться eslint. Кроме того, JSX из коробки понимает typescript с его продвинутым тулингом.


                                        В общем, никаких проблем с поддержкой JSX в редакторах (по крайней мере в тех, которыми пользовался — vim, atom, vscode) я не встречал.

                                        • 0
                                          Особо нового синтаксиса JSX не представляет. И «учить» его намного проще, чем запоминать десятки кастомных конструкций в очередном фреймворке. Тем более, JSX — это не реакт, как принято представлять. Существует много библиотек, использующих DOM API вместо innerHTML, ибо это работает быстрее, особенно на мобильных браузерах. И для этих библиотек используют JSX, т.к. это позволяет писать высокопроизводительный код с удобством простого HTML
                                        • +1
                                          JSX просто удобен, и плевать на идеологию. мне например удобно делать так:

                                          import {dom} from '../inc/dom';
                                          import {WAElement} from '../core/';
                                            
                                          export let login = function(dom: any){ 
                                          
                                              return class Login extends WAElement { 
                                          
                                                  constructor(){         
                                                      super();           
                                                  }                      
                                          
                                                  connectedCallback() {  
                                                      
                                                      let holder = this; 
                                                      let form =         
                                                          <form>         
                                                              <input name='login' placeholder='login' /><br />
                                                              <input name='pwd' placeholder='pwd' type='password' /><br />
                                                              <input type='submit' value='log me' /> 
                                                          </form>        
                                                      ;                  
                                                      
                                                      form.addEventListener('submit', function(evt: any){
                                                                         
                                                          let formData = new FormData(form);  
                                                          holder.sendMessage('authorize', {formData});
                                                          evt.preventDefault();           
                                                      });                
                                                      this.appendChild(  
                                                          <div>          
                                                              { form }   
                                                              <x-auth-sign-up />              
                                                          </div>
                                                      );
                                                  }     
                                              };    
                                          }(dom);
                                          


                                          Просто и удобно. Просто удобно. Чьи религиозные чувства это задевает?
                                          • 0

                                            у меня картинка не загружается, не могу ничего сказать

                                          • 0
                                                        this.appendChild(  
                                                            <div>          
                                                                { form }   
                                                                <x-auth-sign-up />              
                                                            </div>
                                                        );
                                            

                                            Вы же основную нямочку — удобный one-way data flow не используете
                                            • +1
                                              Если что — это не React ) Это объявление кастомного элемента. Я просто показал как удобно когда у тебя по ходу кода верстка в нужный момент становится переменной. Так то в реале весь смак в dom функции — как запилишь так и будет (и декларативный биндинг и state и события)
                                              • 0
                                                >Если что — это не React )

                                                То-то я смотрю и не понимаю. ;-)
                                            • 0
                                              От ES6 шаблонов это отличается несколькими дополнительными кавычками и ${form} вместо { form }, JSX в этом случае выглядит как оверхед.
                                              • 0
                                                раскажите как вот так:
                                                form.addEventListener('submit', function(evt: any)
                                                сделать после объявления элемента в ES6 шаблоне?
                                                • 0

                                                  Очевидно придется поработать с DOM напрямую.


                                                  А React автоматически отключает подобные инлайн листенеры когда элемент уже не используется?


                                                  Я правильно понимаю что React использует even delegation подоход? То есть зарегистрированный явным образом листенер (addEventListener) не добавится к указанному элементу, а просто зарегистрируется как обработчик в одном глобальном листенере топ уровня (на основе генерируемого id компонента или что-то вроде этого)?

                                                  • 0
                                                    >А React автоматически отключает подобные инлайн листенеры когда элемент уже не используется?

                                                    У реакта перманентный анус в нативными листенерами и евентами, поэтому в реакте никто так не делает — там есть свои велосипеды.

                                                    Мы же не реакт обсуждаем а использование jsx вмеcто шаблонизатора (или html-templates в моем случае). У меня в коде вообще реакта нет — это модуль-класс для регистрации кастомного элемента авторизации, то есть потом после регистрации форму авторизации можно воткнуть в любом месте одним тегом.
                                                    • 0
                                                      У меня в коде вообще реакта нет — это модуль-класс для регистрации кастомного элемента авторизации

                                                      Я вот и интересовался как потом этот инлайн обработчик отключается.

                                                      • 0
                                                        нативно, самим броузером. Создается такой же элемент как и div или form, то есть вот тут:
                                                        return class Login extends WAElement
                                                        мы наследуемся от WAElement который обвертка вокруг HTMLElement, то есть все наши кастомы — это обычные html элементы (теги, объекты, в завимости от контекста) и соотв. браузер работает с ними также.
                                                        То есть тут что важно понять — есть jsx, и есть реакт вокруг него (да, надо понимать именно так). Так вот реакт можно убрать и вставить свою функцию сборки дома. И уже от реализации этой функции будет зависеть что мы можем в jsx. У меня например (полусырой код, конечно но уже в принципе работает) идет биндинг если в аттрибутах или содержимом тега указан объект класса state. То есть не надо вообще явно ничего привязывать — в самой верстке указали объект — все, есть биндинг. Стейт элемента можно потом привязать к стейту приложения (в том числе выборочно через фильтры) — все, имеем тот же реакт но на кастомах.
                                                        Пример что я привел — довольно упрощенный, можно например функцию dom настроить так, что если значение аттрибута — функция, то это листенер на событие, имя которого совпадает с именем аттрибута. Тогда dom функция сама будет вешать листенеры, а в аттрибуте достаточно указать имя этой функции. Тоже удобно в некоторых моментах. В общем надо просто захотеть научится это готовить — и только потом уже решать, нравится это или нет (уже умея)
                                                    • 0

                                                      да, там делегация.


                                                      Подробнее об этом ее авторы рассказывали в подкасте
                                                      https://www.youtube.com/watch?v=dRo_egw7tBc&feature=youtu.be

                                              • 0
                                                Оба представленные способы неправильные. :)
                                                Первый — на ровном месте писать код, который ничего не делает.
                                                https://hsto.org/getpro/habr/post_images/9fa/b88/49a/9fab8849a56fd96c3e4f02a998ecad37.png

                                                Второй — шаблонизатор на ровном месте, когда можно обойтись нативным js.

                                                Это как заставить дурака молиться богу. :)
                                                • +1

                                                  A как бы вы оформили второй способ на нативном js?

                                                  • –2
                                                    1. Оказалось, под капотом там куча ерунды типа
                                                    https://habrahabr.ru/post/311226/#comment_9831732

                                                    Зачем?

                                                    2.
                                                    а) просто сцепил (сконкатенировал) бы строки, зачем усложнять? :)
                                                    б) тут иногда говорят, что типа сервер может возвращать для скорения уже откомпилированный шаблон/готовый html.
                                                    Капец, а не проще с помощью jquery ajax-ом дернуть страничку / api и обновить нужный DOM?

                                                    Это псевдопрограммирование. :)

                                                    П.С.
                                                    Спасибо хабру, что при отрицательной карме нельзя вставлять код, очень удобно всем.
                                                    Наказали, так уж наказали.
                                                    • –1
                                                      >Капец, а не проще с помощью jquery ajax-ом дернуть страничку / api и обновить нужный DOM?

                                                      Краткий ответ — не проще.
                                                • +1
                                                  Эх история-история… когда-то, давным-давно, был E4X, но не прижился. Время, шло, история сделал очередной виток выдав JSX (upd: о, так, у них об это и написано)
                                                  • 0

                                                    Видимо важно не только придумать стандарт, но еще и разработать библиотеку, которая этот стандарт использует на пользу себе и пользователям.

                                                    • +1
                                                      Была полная поддержка в FF, и это более 10 лет назад, я даже пробовал его, почему и запомнил, но балом правил ie5-6
                                                    • 0

                                                      и забавный факт, но видимо E4X устарел настолько, что ссылка со страницы про JSX ведет на какой-то совсем другой стандарт: Case for 120 mm HVD-ROM disk

                                                      • 0
                                                        На mdn ещё есть: https://developer.mozilla.org/en-US/docs/Archive/Web/E4X/Processing_XML_with_E4X
                                                        • 0
                                                          Просто на сайте реакта опечатались, 375 vs 357
                                                          • 0
                                                            Да кстати на сайте JSX все правильно (ссылка на 357) — а вот сайт Ecma почему-то автоматом редиректит с 357 на 375 O_o
                                                      • 0
                                                        Идеи E4X были реализованы в Nodejs правда до E4J не дошло. JSX это не виток. Это штопор.
                                                      • +5
                                                        Когда они стали писать HTML в JS, я молчал, я же не пишу HTML в JS.
                                                        Потом они стали писать CSS в JS, а я молчал, я же не пишу CSS в JS.
                                                        А потом они стали писать всё в JS, и уже не было никого, кто бы мог протестовать.
                                                      • +1

                                                        Ваш код можно переписать без единой строчки JS и отдать параллельно верстальщику, программисту и переводчикам:


                                                        $my_cart_position_viewer $mol_viewer
                                                        
                                                            attr * my_cart_position_viewer_selected < isSelected false
                                                        
                                                            childs /
                                                        
                                                                < header $mol_viewer
                                                                    childs / < title \
                                                        
                                                                < imager $mol_imager
                                                                    uri < imageUri \
                                                        
                                                                < counter $mol_number
                                                                    enabledDec < canRemove true
                                                                    value > count 1
                                                                    enabledInc < canAdd true
                                                        
                                                                < messager $mol_viewer
                                                                    childs < messages /
                                                                        < messageOverflow @ \You have reached the limit

                                                        Верстальщик добавит демонстрации компонента в различных состояниях:


                                                        $my_cart_position_viewer_demo $my_cart_position_viewer
                                                            isSelected false
                                                            title \Xperia XYZ
                                                            imageUri \xperia.jpg
                                                            messages /
                                                        
                                                        $my_cart_position_viewer_demo_minimum $my_cart_position_viewer_demo
                                                            count 0
                                                            canRemove false
                                                        
                                                        $my_cart_position_viewer_demo_long_selected $my_cart_position_viewer_demo
                                                            isSelected true
                                                            title \Computer with screen, mouse, keyboard and foot heater
                                                            count 1
                                                        
                                                        $my_cart_position_viewer_demo_maximum $my_cart_position_viewer_demo
                                                            count 2
                                                            canAdd false
                                                        
                                                        $my_cart_position_viewer_demo_over9000 $my_cart_position_viewer_demo
                                                            count 9001
                                                            canAdd false
                                                            messages / < messageOverflow

                                                        И застилизует:


                                                        [my_cart_position_viewer] {
                                                            display: flex;
                                                            padding: .5rem;
                                                        }
                                                        
                                                        [my_cart_position_viewer_selected] {
                                                            background: #fed;
                                                        }
                                                        
                                                        [my_cart_position_viewer_header] {
                                                            flex: 1 1 15rem;
                                                            font-weight: bold;
                                                            padding: .5rem;
                                                        }
                                                        
                                                        [my_cart_position_viewer_counter] {
                                                            flex: 0 0 2rem;
                                                        }
                                                        
                                                        [my_cart_position_viewer_messager] {
                                                            color: red;
                                                            flex: 1 1 15rem;
                                                            padding: .5rem;
                                                        }

                                                        А программист возьмёт доменные модели:


                                                            export interface $my_product {
                                                                name() : string
                                                                available() : number
                                                                thumbUri() : string
                                                            }
                                                        
                                                            export interface $my_cart_position {
                                                                count( ...diff : number[] ) : number
                                                                product() : $my_product
                                                            }

                                                        И опишет их преобразование в интерфейсную модель, добавив дополнительную интерфейсную логику:


                                                            export class $my_cart_position_viewer extends $.$my_cart_position_viewer {
                                                        
                                                                position() {
                                                                    return < $my_cart_position > null
                                                                }
                                                        
                                                                title() {
                                                                    return this.position().product().name()
                                                                }
                                                        
                                                                imageUri() {
                                                                    return this.position().product().thumbUri()
                                                                }
                                                        
                                                                count( ...diff : number[] ) {
                                                                    return this.position().count( ...diff )
                                                                }
                                                        
                                                                canRemove() {
                                                                    return this.count() > 0
                                                                }
                                                        
                                                                canAdd() {
                                                                    return this.count() < this.position().product().available()
                                                                }
                                                        
                                                                isOverflow() {
                                                                    return this.count() > this.position().product().available()
                                                                }
                                                        
                                                                messages() {
                                                                    return [
                                                                        this.isOverflow() ? this.messageOverflow() : null
                                                                    ]
                                                                }
                                                        
                                                            }

                                                        А тем временем переводчики переведут текст "You have reached the limit" на все языки мира, получив следующего вида json:


                                                        {
                                                            "$my_cart_position_viewer_messageOverflow": "You have reached the limit"
                                                        }

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

                                                        • 0
                                                          Вам не кажется, что настолько много гибкости мало кому нужно? :)
                                                          • 0
                                                            Ещё бы оно не пользовало клятого убийцу мизинчиков $
                                                          • –3
                                                            Мы строим приложения на реакте с первых его версий.

                                                            Сначала не использовали JSX (typescript не поддерживал), и еще жив и развивается проект где его нет (т.е. там dom.div({ className: 'item'}).

                                                            Потом JSX пришел, и мы радостно начали писать на нём.

                                                            Потом пошли делать фичу в проект без JSX, и заплакали от счастья и радости.

                                                            Нативный синтаксис с DOM.div — компактнее, позволяет использовать больше фичей языка, его проще редактировать, у него нет проблем с тулзами и редакторами.

                                                            JSX — в топку.
                                                            • 0

                                                              Начиная с версии 1.6 в Typescript появилась поддержка JSX. Достаточно создавать файл с расширением .tsx


                                                              Поддержка в редакторах тоже улучшилась, поэтому может вам стоит попробовать TSX еще раз.

                                                              • 0
                                                                Похоже ты не прочитал сообщение. Там написано: «Потом JSX пришел, и мы радостно начали писать на нём.».

                                                                У меня на JSX два весьма немаленьких проекта, и два немаленьких проекта — без. Без JSX — намного лучше.
                                                              • 0
                                                                А какие фичи недоступны в JSX? Single root element обходится тем, что можно вернуть массив, а что еще?
                                                                • 0
                                                                  Всякие приятные синтаксические штуки JS недоступны:
                                                                  var className = ...; return dom.div({ className }) 
                                                                  
                                                                  var eventName = immidiate ? 'onKeydown' : 'onBlur'; 
                                                                  return dom.div({ [eventName]: this.validate })
                                                                  


                                                                  Всякие привычные удобняшки усложняются или невозможны вообще:
                                                                  var element = isInline ? dom.div : dom.span; return element({ ... })
                                                                  
                                                                  dom.div({}, isVisible && dom.span({}, "Hello")) // так можно и с JSX, но появляется лишний уровень скобок
                                                                  
                                                                  var b = new BemDomFactory('my-list'); // несложный велосипед, создаем до компонента
                                                                  // in render():
                                                                  b.div({ element: 'header', mods: [isRed && 'red'] }); // class='my-list__header--red
                                                                  
                                                                  • 0
                                                                    На самом деле, всё, кроме последнего, легко делается на JSX

                                                                    1 и 2 делаются через spread operator, он уже stage2 вроде бы.
                                                                    <div {...{className, [eventName]: this.validate}}/>
                                                                    


                                                                    Третье:

                                                                    var Element = isVisible? <div/>: <span/>

                                                                    <Element .....>

                                                                    <div>{isVisible && <span>Hello</span>}</div>
                                                                    

                                                                    Вполне сработает. Тут другой подводный камень:
                                                                    var b = false
                                                                    <div>{b}</div>
                                                                    

                                                                    Выведет
                                                                    <div></div>
                                                                    

                                                                    а не
                                                                    <div>false</div>
                                                                    

                                                                    как можно было предположить. Так сделано именно для того, чтобы можно было писать {b && <div/>}
                                                                    Последний пример, теоретически, можно сделать как

                                                                    React = new BemDomFactory('my-list');
                                                                    и потом
                                                                    <div ...../>

                                                                    • 0

                                                                      Более того, spread в jsx и spread в js-объектах, это разные сущности. Чтобы это заработало


                                                                      <div {...props} /> 

                                                                      достаточно подключить babel-preset-react, stage-2 тут не нужен.

                                                                      • 0
                                                                        >spread в jsx и spread в js-объектах, это разные сущности.

                                                                        О сколько нам открытий чудных… ;-)
                                                                        • 0

                                                                          Достаточно посмотреть во что превращается код после Babel


                                                                          const props = {...source};
                                                                          //станет
                                                                          var props = Object.assign({}, source);

                                                                          <div {...props} />
                                                                          //станет
                                                                          React.createElement("div", props);

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

                                                                      • 0
                                                                        Делая так:

                                                                        <div {...{className, [eventName]: this.validate}}/>


                                                                        — ты используешь специальный JSX-синтаксис, который позволяет переключиться назад на JS-синтаксис, чтобы не пользоваться ограниченным JSX-синтаксисом для атрибутов :)

                                                                        Остается сделать еще один шаг, и отказаться от JSX-синтаксиса для элементов.
                                                                • +2

                                                                  Чем лично мне, как программисту (не верстальщику) удобен jsx.
                                                                  Оговорюсь сразу, что использую тайпскрипт и tsx, но многие вещи справедливы и без тайпскрипта:


                                                                  • Строгая типизация шаблонов и кастомных компонентов. Тайпскрипт подсказывает свойства и события, компилятор показывает ошибки в шаблонах.


                                                                  • Удобная работа с children. Как в ангуляре удобно работать с содержимым компонента? Никак, только через боль и страдания, через парсинг строк, обработку дом-узлов и transclude. В Реакте это просто объекты, можно обрабатывать обычным кодом.


                                                                  • Расширение и декорация компонентов и классов компонентов. Метапрограммирование для бедных. Но лучше, чем в строковых и dom-based шаблонах.


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

                                                                  Однако, jsx в чем-то неуловимо раздражает. Постоянно спотыкаешься на className. Зачем это было делать?!


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

                                                                  • 0

                                                                    Можно всегда вынести верстку (JSX) в сторону и дать доступ верстальщикам (при должной организации).

                                                                    • 0

                                                                      className нужен потому, что еще поддерживается браузер IE8, в котором class не может использоваться в качестве ключа в объекте


                                                                      <div class="test" />

                                                                      станет таким


                                                                      React.createElement('div', {
                                                                        class: 'test' // IE не распарсит эту строку
                                                                      })

                                                                      Насчет разделения работы верстальщика и девелопера могу предложить подход presentational and container components. В presentational собирается одна верстка, а логика содержится в специальных container components, где верстки почти нет.

                                                                      • 0

                                                                        Ну хоть в JSX могли бы разрешить class. Хотя однообразие, конечно.

                                                                        • 0

                                                                          Сейчас покопался в интернете, нашел объяснение Бена, в чем дело:


                                                                          мы смотрим на свойства html (типа el.className=...), а не атрибуты (el.setAttribute('class', ...)), если это возможно. Атрибуты это всегда строки, в то время как свойства могут быть любым доспустимым в Javascript значением, что дает больше гибкости в некоторых местах. Например, мы можем воспользоваться свойством classList которое больше вписывается в нашу модель, чем простой className. Сейчас React не поддерживает classList, но в будущем сможет. Так что при условии, что className ведет себя как соответствующее свойство html [ноды], имеет смысл придерживаться именования className
                                                                      • 0
                                                                        Читал — есть компании, где всё же верстальщики пишут JSX.
                                                                        Потом программисты пишут уже код.

                                                                        Так и живут. Пишут, что нормально. Притёрлись. ;-)
                                                                        • 0

                                                                          Angular 2 все Ваши пункты покрывает с горкой.

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

                                                                          Что не так с модульностью в Ангуляр 1 (и причем зедсь вообще Ангуляр 1, модульность это базовая/абстрактная вещь)?
                                                                          • +1

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

                                                                            • +1
                                                                              В результате сложно найти все места, которые ссылаются на определенную зависимость. Второе, зависимости указываются по строковым именам, что неудобно.

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


                                                                              @Component({
                                                                                  __filename,
                                                                                  bindings: {_input: '< input'}
                                                                              })
                                                                              class Controller extends require('./../common/base-class') {
                                                                                  static $inject = [
                                                                                      require('./../common/crud-service').$name,
                                                                                      require('./hr-expert-data-service').$name,
                                                                                      '$scope',
                                                                                      '$q'
                                                                                  ];
                                                                              
                                                                                  constructor(Crud, expertDataService, $scope, $q) {
                                                                                      super({Crud, expertDataService, $scope, $q});
                                                                                  }

                                                                              @Component — самописная обертка в стиле второго ангуляра. $name во все сущности ангуляровские подставляется на основе имени файла автоматически (по переданному значению __filename). В базовом конструкторе {Crud, expertDataService, $scope, $q} (зависимости) линкуются в отдельное поле объекта.

                                                                              • 0

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

                                                                                • 0

                                                                                  У меня изначально было name, когда еще функции использовал вместо классов, но function.name не все браузеры понимали, перешел на $name.

                                                                                  • +1

                                                                                    Кроме этого имя функций должно быть минифицировано при сжатии JS.

                                                                          • 0
                                                                            Хотя исторически причиной отделения HTML и JS было разделение статики и динамики, что уже неактуально для рендеринга на клиенте

                                                                            Исторически причиной разделения HTML и JS было то, что таким образом разделялась логика и представление, что позволяло, в свою очередь, работать почти одновременно верстальщику и программисту – каждому в своей части.
                                                                            • 0

                                                                              Когда я это писал, у меня в уме представлялась типичная CMS на PHP, в которой есть html-верстка с вкраплениями php-сниппетов. С другой стороны был Javascript-код, которым показывались анимации, галереи картинок и т.д.


                                                                              Где здесь логика, где представление?

                                                                            • 0

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

                                                                              • 0
                                                                                для чистых верстальщиков есть css.
                                                                                • 0

                                                                                  Глупости. Я не сторонник наличия в команде чистых верстальщиков, мне удобнее когда в команде работают более хардкорные люди. Но все таки чистые верстальщики еще не вымерли, и в моем понимании это html + css + less/sass.

                                                                                  • 0

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


                                                                                    Вот статья, c пояснением этого подхода.

                                                                              • 0
                                                                                Я не понял, а при чём тут JSX?
                                                                                • 0
                                                                                  Этого никто не понимает. JSX похож на шаблон, но это только так кажется.
                                                                                  А с шаблонами народ привык уже работать.
                                                                                  Имхо.
                                                                                • +1

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


                                                                                  Как по мне, производительность у Реакта достаточная для большинства случаев, кроме того, есть еще запас по оптимизации. Конечно, он медленее идеального обновления ДОМ вручную.


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

                                                                                  • –1
                                                                                    Приехали.

                                                                                    Пропагандисты говорили, что DOM медленное говно, а их поделки — д«Артаньяны.
                                                                                    На деле же поделки оказались сами говном. :)
                                                                                    А-ха-ха. :)
                                                                                    • 0

                                                                                      Да ладно вам. В соседней теме на Ext JS разрабатывали, и не смущала производительность до поры :)

                                                                                      • 0
                                                                                        Ext JS — это супер-мощная штука. Несколько сот классов. Под 400!

                                                                                        Но вот чего-то задвинут на задворки ентерпрайза. :-0
                                                                                  • 0
                                                                                    Также у Реакта наиболее "дешевое", с точки зрения производительности, дробление на компоненты — каждый компонент — это функция (либо класс), а в Ангуляре, например, это дополнительная куча watcher-ов.

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


                                                                                    Как по мне риакт далеко не уникален, и это просто хайп вокрг него и ничего более. Кроме того он слишком усложняет дело со своим вирруальным DOM деревом, вычисляя что именно патчить в реальном дереве. Я бы лучше посмотрел в сторону Riot JS.

                                                                                    • +1
                                                                                      >Я бы лучше посмотрел в сторону Riot JS.

                                                                                      http://todomvc.com/examples/riotjs/

                                                                                      1. добавляем два итема в туду лист
                                                                                      2. переходим в Active
                                                                                      3. отмечаем первый элемент активным
                                                                                      4. наслаждаемся косяками RiotJS

                                                                                      Уже бежим переходить на такую замечательную библиотеку :)
                                                                                      • 0

                                                                                        Я в код не смотрел, но обычно баг имплементации не указывает на баг инструмента.

                                                                                        • +1
                                                                                          Я в код смотрел и общался с разработчиками, и полная некомпетентность его авторов отлично демонстрирует качество инструмента.
                                                                                          • 0

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

                                                                                            • 0
                                                                                              https://github.com/riot/riot/issues/484 (тут суть не в производительности, а в том что они там просирают внутреннее состояние)

                                                                                              Уже столько времени прошло, а они до сих пор не понимают важности того что не нужно терять внутренее состояние дом элементов и до сих пор прячут неявную магию по которой вычисляется как находить перестановку элементов, которая в итоге не работает в куче случаев.
                                                                                              • –1
                                                                                                до сих пор прячут неявную магию по которой вычисляется как находить перестановку элементов

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


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

                                                                                                • +1
                                                                                                  >Я бы сказал ценность виртуального DOM переоценена

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

                                                                                                  Проблема в основном с тем что люди ассоциируют производительность виртуального дома с реактом, реакт просто первым реализовал эту идею, но его реализация очень медленая и сейчас достаточно сложно внести какие-то изменения в реакт чтобы его ускорить, придётся полностью его переписывать. Мы с автором Bobril'а ещё два года назад продемонстрировали как можно реализовать очень быстрый виртуальный дом, с тех пор на этих идеях начали появляться реализации React API, например Inferno, и еслиб реакт переписывали, то вероятно бы реализовали его так же как современные виртуал дом либы https://twitter.com/sebmarkbage/status/776148675592544256
                                                                                                  • 0

                                                                                                    Вот вот, от риакта осталось одно название.

                                                                                                    • 0
                                                                                                      Ценность реакта в экосистеме и громадном комьюнити. Практически любую проблему можно решить воспользовавшись гуглом, сейчас это наиболее предсказуемый инструмент если нужно решать какую-то задачу и не хипстерить.
                                                                                                      • –1

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

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

                                                                                                          Серьёзные проекты делают на Ext.js — который не собирается сдавать позиции в своей нише.
                                                                                                            • 0
                                                                                                              Я читал это.

                                                                                                              У них не серьёзные проекты. :-)

                                                                                                              Если без шуток — они просто испугались Ext.js 6-й версии. Очень мощная штука.
                                                                                                              Если бы было просто перепрыгнуть с 4-й версии Ext.js на 6-ю — вопросов бы не возникало — писали бы дальше на Ext.js.

                                                                                                              А так да, очень много УЖЕ разработанных (в том числе сторонних свободных) компонентов для Ext.js 4-й версии просто отказываются работать и в 5-й и в 6-й версии Ext.js.

                                                                                                              Отсюда все ноги и растут. Имхо.
                                                                                      • +1

                                                                                        Реакт не более чем инструмент, не понимаю, почему хайп вокруг него так завышает ожидания :)


                                                                                        Не фреймворк, продвинутый темплейтер, оптимизации — именно это и делает его таким удобным (для меня). И еще гладкая и удобная поддержка современного джаваскрипта.


                                                                                        Кроме того он слишком усложняет дело со своим вирруальным DOM деревом, вычисляя что именно патчить в реальном дереве.

                                                                                        А почему он слишком усложняет? Ну я понимаю, что алгоритмы там нетривиальные, но это же все скрыто, с ним не нужно взаимодействовать (за исключением оптимизаций, но там тоже не виртуальный ДОМ).

                                                                                      • 0
                                                                                        JavaScript в JSX — это возможность для создания шаблонов с ветвлениями и циклами и для создания отзывчивых шаблонов. Почему это плохо? Плохо, когда JS в JSX используют для создания бизнес-логики, но ведь это не вина JSX.
                                                                                        • 0

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