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


Довольно часто приходится слышать, что 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 в код компонента не так уж плохо и приносит пользу в некоторых случаях.



Комментарии (216):

  1. nuit
    /#9831518

    https://www.youtube.com/watch?v=mVVNJKv9esE&t=1220

    • nazarpc
      /#9831582

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


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

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

      • justboris
        /#9831732 / +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.

        • nazarpc
          /#9831806 / +9

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


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

          • DGolubets
            /#9831856 / -1

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

            • nazarpc
              /#9831868 / +2

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


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

          • wert_lex
            /#9831860 / +3

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

            • nazarpc
              /#9831876 / +1

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


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


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

          • justboris
            /#9831870

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


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


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

            • nazarpc
              /#9831888 / +1

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


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


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


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

              • i360u
                /#9832342

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

                • nazarpc
                  /#9832344

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

                  • i360u
                    /#9832386

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

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

                    • nuit
                      /#9832420

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

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

                      • i360u
                        /#9832432

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

                        • nuit
                          /#9832458

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

                          • i360u
                            /#9832542

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

                            • nuit
                              /#9832574

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

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

                              • i360u
                                /#9832604

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

                                • nuit
                                  /#9832668

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

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

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

                                  • i360u
                                    /#9832704

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

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

                                    • nuit
                                      /#9832714

                                      Компоненты в реакте могут и не создавать 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

                                      • i360u
                                        /#9832766

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

                                        • nuit
                                          /#9832788 / +1

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

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

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

                                          • i360u
                                            /#9832938

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

                                            • nuit
                                              /#9832970

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

                                            • indestructable
                                              /#9833388

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


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

                                              • nuit
                                                /#9833414

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

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

                                            • G-M-A-X
                                              /#9833478 / -1

                                              i360u с ними спорить бесполезно.

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

                                              • nuit
                                                /#9833488

                                                Разве тут кто-то спорит? Я лишь хочу узнать что это за «оптимизации работы браузера с веб-компонентами (пока конечно только в Хроме но скоро и в остальных браузерах).» Больше меня ничего не интересует :)

                              • arvitaly
                                /#9832606

                                Ничего в них громоздкого нет, это те же самые JS-объекты.

            • i360u
              /#9832332

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

          • dema
            /#9841886

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

            • gearbox
              /#9843156

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

              • justboris
                /#9843192

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


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

                • gearbox
                  /#9843228

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

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

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

                  • justboris
                    /#9843278

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


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


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


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


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

                    • vintage
                      /#9843444

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

                      • dema
                        /#9843602

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

                        • vintage
                          /#9843672

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

                      • justboris
                        /#9843734

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

                    • gearbox
                      /#9843450

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

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

  2. jMas
    /#9831522

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

  3. nazarpc
    /#9831560

    Импользование 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.

    • justboris
      /#9831606 / +3

      Добрый день!


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


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


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


      [[if(isOverLimit, warningText)]]

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


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

      • k12th
        /#9831630 / -1

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

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


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

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

        • MorozoW
          /#9831854

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

          • reactoranime
            /#9833018

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

      • nazarpc
        /#9831634

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


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


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


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

  4. k12th
    /#9831568 / +1

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


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


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


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

    • gearbox
      /#9831596 / -3

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

    • justboris
      /#9831626 / +1

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


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


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

      • k12th
        /#9831632

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

      • nazarpc
        /#9831646

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

        • gibson_dev
          /#9831938

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

          • nazarpc
            /#9831952 / +1

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

            • gibson_dev
              /#9831960 / +2

              Производительность DOM тут не главное, тут главное общая производительность (и библиотек и программиста который это все обслуживает) а разница между 55 и 99 мс не такая и страшная

    • Laney1
      /#9831674 / +2

      Но JSX — это новый синтаксис. Нужна поддержка со стороны редакторов, IDE, линтеров, прочих инструментов

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


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

    • SPAHI4
      /#9832660

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

  5. gearbox
    /#9831572 / +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);
    


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

    • justboris
      /#9831578

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

    • TheShock
      /#9831604

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

      Вы же основную нямочку — удобный one-way data flow не используете

      • gearbox
        /#9831614 / +1

        Если что — это не React ) Это объявление кастомного элемента. Я просто показал как удобно когда у тебя по ходу кода верстка в нужный момент становится переменной. Так то в реале весь смак в dom функции — как запилишь так и будет (и декларативный биндинг и state и события)

        • taujavarob
          /#9832162

          >Если что — это не React )

          То-то я смотрю и не понимаю. ;-)

    • serf
      /#9832300

      От ES6 шаблонов это отличается несколькими дополнительными кавычками и ${form} вместо { form }, JSX в этом случае выглядит как оверхед.

      • gearbox
        /#9832544

        раскажите как вот так:
        form.addEventListener('submit', function(evt: any)
        сделать после объявления элемента в ES6 шаблоне?

        • serf
          /#9832954

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


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


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

          • gearbox
            /#9833032

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

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

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

            • serf
              /#9833038

              У меня в коде вообще реакта нет — это модуль-класс для регистрации кастомного элемента авторизации

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

              • gearbox
                /#9833132

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

  6. G-M-A-X
    /#9831642

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

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

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

    • justboris
      /#9831768 / +1

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

      • G-M-A-X
        /#9832124 / -2

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

        Зачем?

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

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

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

        • taujavarob
          /#9832182 / -1

          >Капец, а не проще с помощью jquery ajax-ом дернуть страничку / api и обновить нужный DOM?

          Краткий ответ — не проще.

  7. RubaXa
    /#9831680 / +1

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

    • justboris
      /#9831754

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

      • RubaXa
        /#9831778 / +1

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

    • justboris
      /#9831758

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

      • RubaXa
        /#9831782

        На mdn ещё есть: https://developer.mozilla.org/en-US/docs/Archive/Web/E4X/Processing_XML_with_E4X

      • Kain_Haart
        /#9832040

        Просто на сайте реакта опечатались, 375 vs 357

        • VasilioRuzanni
          /#9833538

          Да кстати на сайте JSX все правильно (ссылка на 357) — а вот сайт Ecma почему-то автоматом редиректит с 357 на 375 O_o

    • babylon
      /#9842560

      Идеи E4X были реализованы в Nodejs правда до E4J не дошло. JSX это не виток. Это штопор.

  8. zapolnoch
    /#9831750 / +5

    Когда они стали писать HTML в JS, я молчал, я же не пишу HTML в JS.
    Потом они стали писать CSS в JS, а я молчал, я же не пишу CSS в JS.
    А потом они стали писать всё в JS, и уже не было никого, кто бы мог протестовать.

    • justboris
      /#9831764

      я бы написал про CSS в JS тоже, но у меня нет такого опыта.


      Был бы рад если кто-то расскажет, чем это может быть полезно.

  9. vintage
    /#9831996 / +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"
    }

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

    • G-M-A-X
      /#9832136

      Вам не кажется, что настолько много гибкости мало кому нужно? :)

    • domix32
      /#9832142

      Ещё бы оно не пользовало клятого убийцу мизинчиков $

  10. jakobz
    /#9832238 / -3

    Мы строим приложения на реакте с первых его версий.

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

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

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

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

    JSX — в топку.

    • justboris
      /#9832686

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


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

      • jakobz
        /#9832968

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

        У меня на JSX два весьма немаленьких проекта, и два немаленьких проекта — без. Без JSX — намного лучше.

    • dema
      /#9841902

      А какие фичи недоступны в JSX? Single root element обходится тем, что можно вернуть массив, а что еще?

      • jakobz
        /#9841918

        Всякие приятные синтаксические штуки 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
        

        • dema
          /#9841946

          На самом деле, всё, кроме последнего, легко делается на 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 ...../>

          • justboris
            /#9842420

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


            <div {...props} /> 

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

            • taujavarob
              /#9843070

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

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

              • justboris
                /#9843100

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


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

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

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

          • jakobz
            /#9848396

            Делая так:

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


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

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

  11. indestructable
    /#9832248 / +2

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


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


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


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


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

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


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

    • jMas
      /#9832298

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

    • justboris
      /#9832706

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


      <div class="test" />

      станет таким


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

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

      • indestructable
        /#9833394

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

        • justboris
          /#9833810

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


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

    • taujavarob
      /#9833624

      Читал — есть компании, где всё же верстальщики пишут JSX.
      Потом программисты пишут уже код.

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

    • PFight77
      /#9843676

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

  12. serf
    /#9832296

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

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

    • indestructable
      /#9832450 / +1

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

      • serf
        /#9832900 / +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} (зависимости) линкуются в отдельное поле объекта.

        • indestructable
          /#9833404

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

          • serf
            /#9833500

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

            • serf
              /#9833518 / +1

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

  13. sd_baron
    /#9832708

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

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

    • justboris
      /#9832718

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


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

  14. serf
    /#9833064

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

    • gearbox
      /#9833138

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

      • serf
        /#9833154

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

        • justboris
          /#9833184

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


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

  15. Asgator
    /#9833164

    Я не понял, а при чём тут JSX?

    • taujavarob
      /#9833660

      Этого никто не понимает. JSX похож на шаблон, но это только так кажется.
      А с шаблонами народ привык уже работать.
      Имхо.

  16. indestructable
    /#9833446 / +1

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


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


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

    • G-M-A-X
      /#9833636 / -1

      Приехали.

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

      • indestructable
        /#9834254

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

        • taujavarob
          /#9834272

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

          Но вот чего-то задвинут на задворки ентерпрайза. :-0

  17. serf
    /#9833664

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

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


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

    • nuit
      /#9833682 / +1

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

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

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

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

      • serf
        /#9833688

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

        • nuit
          /#9833694 / +1

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

          • serf
            /#9833698

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

            • nuit
              /#9833716

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

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

              • serf
                /#9833726 / -1

                до сих пор прячут неявную магию по которой вычисляется как находить перестановку элементов

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


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

                • nuit
                  /#9833786 / +1

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

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

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

                  • serf
                    /#9833818

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

                    • nuit
                      /#9833840

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

                      • serf
                        /#9833852 / -1

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

                        • taujavarob
                          /#9834306

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

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

                            • taujavarob
                              /#9834330

                              Я читал это.

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

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

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

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

    • indestructable
      /#9834260 / +1

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


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


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

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

  18. Finesse
    /#9834826

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

    • vintage
      /#9835088

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

      • indestructable
        /#9835146

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

        • taujavarob
          /#9835232

          >Невозможно же сделать реально применимый шаблонизатор без циклов и условий, разве не так?

          Это уже интересно. К, примеру, имеем цикл, а в какой последовательности проводить итерацию? Вот на этот вопрос где даётся ответ? В JSX непосредственно или где?

        • justboris
          /#9835250

          XSLT с вами не согласится.
          Конечно, это изврат и так шаблонизировать сложно, но возможно.


          А обычные шаблонизаторы типа handlebars или jade производят на выходе такой же js-код, как вы бы написали сами. Так есть ли смысл прятаться за абстракцию шаблонизатора, если на JS+JSX неплохо выходит.

          • indestructable
            /#9839110

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


            В JSX тоже можно при желании написать нечто вроде:


            <ul>
                <Each set={ items } 
                      renderItem=>{ this.renderListItem }>
                </Each>
            </ul>

            Только это лишнее усложнение.

        • vintage
          /#9835352

          А при чём тут бизнес-логика?


          Я чуть выше привёл обстоятельный пример шаблонизатора без циклов и условий.

          • indestructable
            /#9839220

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

  19. taujavarob
    /#9835222

    del

  20. PFight77
    /#9836466

    Основная беда JSX в том, что он страшно выглядит как шаблон. Он позволяет делать все что угодно, но простые вещи — if, for в нем смотрятся не очень. Вот примеры для сравнения, React и Angular2:

    Условие:

    <div>
        { this.state.loading  &&
            <div class="loading-icon"> </div>
        }
    </div>
    

    <div>
        <div class="loading-icon" *ngIf="loading"> </div>
    </div>
    


    Цикл:
    <ul>
        { this.state.items.map(item => 
            <li >{item.name} </li>
        )}
    </ul>
    

    <ul>
        <li *ngFor="let item in items" >{{item.name}}</li>
    </ul>
    

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

    • justboris
      /#9836558 / +1

      На эту тему есть вот такая страничка сравнения:
      http://jeffcarp.github.io/frontend-hyperpolyglot/


      Кроме того, обычно в React шаблонах не пишут долгие цепочки с this, а создают переменные заранее


      const {loading} = this.state;
      return <div>{loading && <div class="loading-icon"></div>}</div>

      Получается не менее компактно, чем в Angular, да еще и более нативно. С циклом то же самое.


      Элемент цикла можно не просто вынести в отдельную функцию, но и использовать ее как React-компонент


      function ListItem({title}) {
        return <li>{title}</li>
      }
      
      function List({items}) {
         return <ul>{items.map(item => <ListItem item={item} />)}</ul>
      }

      React-компонентом может быть любая функция, возвращающая JSX.


      Зачем вам нужно знать, каким станет html полностью? Вы работаете на своем уровне абстракции, дочерние компоненты отдельно, на их реализацию можно посотреть потом, если захочется

      • taujavarob
        /#9836622

        justboris > Зачем вам нужно знать, каким станет html полностью? Вы работаете на своем уровне абстракции, дочерние компоненты отдельно, на их реализацию можно посотреть потом, если захочется

        Отлично написали.

        PFight77 > Основная беда JSX в том, что он страшно выглядит как шаблон. Он позволяет делать все что угодно, но простые вещи — if, for в нем смотрятся не очень.

        Эстетичный подход — это конечно хорошо. :-)

        Но стоп, «простые вещи» в JSX есть простой(!) Javasript код.
        Он(код) по определению не может выглядеть страшнее, чем «некия» странные *ngIf, *ngFor и им подобные.

      • taujavarob
        /#9836632

        Наверное, тут вернее будет так:
        … ListItem title={item}…

        • justboris
          /#9836688

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

      • PFight77
        /#9836668 / +1

        От того, что Вы записали в одну строчку код более красивым не стал: )) И да, на практике объявлять кучу переменных в начале функции лично мне всегда лень. И всем моим коллегам. Да к тому же, появляется лишняя степень индирекции, чтобы понять откуда берется значение необходимо это отследить. Лишняя сложность для понимания и отладки.


        Зачем вам нужно знать, каким станет html полностью?

        Затем, что, собственно, это и есть цель любой подобной технологии — породить html. Есть результат который у меня в голове, и есть средства, которыми я его добиваюсь.


        Ну а если без громких фраз:


        1. Прежде всего для верстки. К сожалению, css не так прост. Часто требуется добавлять всякие врапперы, менять порядок элементов и прибегать к прочим подобным приемам, чтобы добиться нужного вида и поведения макета. Часто для правильной верстки отдельной области нужно контролировать отдельные ее части. Поэтому для верстальщика важно видеть html целиком, и иметь возможно легко его менять. Плохо здесь именно разбиение шаблона даже в рамках одного компонента, с разбиением на дочерние компоненты еще можно смириться. Хотя я всегда предпочитаю не плодить слишком много мелких компонентов. Я считаю, что под-компонент есть смысл выделять, если он содержит хотя бы десяток строк html и сколько-то логики (за исключением простых, часто используемых stateless).
        2. Для отладки. Допустим, тех же багов в верстке. Я нахожу через DevTools в браузере проблемное место в html, и хочу найти код, где данный html рождается. В react это становится проблемой, т.к. код разбросан по куче мелких функций. Хорошо если find all по имени класса получится.
        3. Для простоты восприятия. Сколько бы мы не говорили про модульность и гибкость, это все вспомогательные вещи. Главное — результат. Если мы генерируем html, результат — картинка в браузере. В конечном счете я хочу получить конкретный макет, конкретный вид сайта. И я хочу понимать, как эта картинка сформируется. Дробление шаблонов в React осложняет это понимание.

        • indestructable
          /#9839236

          Это все справедливо, но не только для Реакта. В Ангуляре все то же самое, да, думаю, и в любом другом фреймворке тоже.


          Главное — результат. Если мы генерируем html, результат — картинка в браузере. В конечном счете я хочу получить конкретный макет, конкретный вид сайта. И я хочу понимать, как эта картинка сформируется. Дробление шаблонов в React осложняет это понимание.

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

        • taujavarob
          /#9839614 / +1

          PFight77 >Дробление шаблонов в React осложняет это понимание.

          Все во все времена пытались избавиться от «монолита», а тут вывод о том, что «дробление шаблонов в React осложняет это понимание».

          «Неисповедимы пути твои… » ©

          • PFight77
            /#9840076

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

            • taujavarob
              /#9840090

              PFight77 > Я, как уже писал, сторонник компонентов среднего размера — достаточных для редуцирования сложности, но при этом не на столько маленьких,

              Не боитесь остаться в одиночестве?: «1. Функции должны быть маленькими. Совсем маленькими.»
              https://habrahabr.ru/post/310590/

              • PFight77
                /#9840104 / +1

                Функции, но не шаблоны HTML. Я привел аргументы выше, почему именно HTML нельзя сокращать до одной строчки.


                В этом беда ReactJS, он рассматривает формирование HTML как алгоритм (часть JavaScript), а не как построение по шаблону. Отсюда и маленькие функции, как Вы верно заметили.

                • taujavarob
                  /#9840114

                  PFight77 > >В этом беда ReactJS, он рассматривает формирование HTML как алгоритм (часть JavaScript), а не как построение по шаблону.

                  В этом его фишка (революционная особенность). Имхо.

                • taujavarob
                  /#9841326 / +1

                  PFight77 >В этом беда ReactJS, он рассматривает формирование HTML как алгоритм (часть JavaScript), а не как построение по шаблону. Отсюда и маленькие функции, как Вы верно заметили.

                  Это не беда — это философия. ;-)

                  Да, очевидно что БОЛЬШОЙ монолит — это плохо.

                  Но вот вы ратуете за средний(!) монолит — ну, типа чтобы код на страницу влезал при минимуме прокрутки. — Да, это будет также более понятно чем мелко-функциональный код — ибо, и это очевидно, именно так и пишут Hello-World всякие — именно чтобы читающий ПОНЯЛ код не отвлекаясь на организацию кода, на разбивку кода на мелкие функции(тратя своё внимание не на понимание а на поиск взаимосвязей).

                  Но после осознания Hello-World начинаются… рабочие будни — и там новая философия — чем мельче тем лучше!

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

                  Вы же ратуете за продолжение использовать философию Hello-World и дальше. В этом ваша ошибка. Имхо.

                  • vintage
                    /#9841842

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

                    • taujavarob
                      /#9841864

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

                      Повторю за dema > Не-не-не… Ну чесслово, если angular и react еще выглядят хоть как-то понятно, то вот это очень похоже на язык K. :)

                      Вот, если там(angular и react) хоть отдалённо напоминает старый добрый HTML — то у вас НОВЫЙ язык.

                      Я думаю, что разработчики JSX могли предложить ЛЮБОЙ синтаксис своего JSX (там всё равно через транспиллер его надо прогонять), но, поразмыслив, остановились (пока?) на неком гибриде старого доброго HTML — Чтобы… не пугать девелоперов! имхо. :-)

                      • vintage
                        /#9841900

                        Лучше бы попугали, чтобы не получалось таких перлов:


                        class MyApp extends React.Component {
                            render() { return (
                                <MyPanel
                                    head={
                                        <MyHeader
                                            title="My Tasks"
                                            closable={ true }
                                        />
                                    }
                                    body={
                                        <MyTaskList
                                            assignee="me"
                                            status="todo"
                                        />
                                    }
                                />
                            ) }
                        }

                        Для сравнения, то же самое на view.tree:


                        $my_app $mol_viewer
                            childs /
                                < panel $my_panel
                                    head < header $my_header
                                        title \My Tasks
                                        closable true
                                    body < bodier $my_task_list
                                        assignee \me
                                        status \todo

                        • taujavarob
                          /#9841906

                          >Лучше бы попугали, чтобы не получалось таких перлов:

                          Так выше всё родное — XML код, уже лет 10 как привычен то всюду. ;-)

                          • vintage
                            /#9841916

                            У вас видимо встроенный валидатор сломался :-)

                        • dema
                          /#9841926

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

                          <A>
                            <B/>
                          </A>
                          

                          эквивалентно
                          <A children={<B/>} />
                          

                          ну или
                          <A children={[<B/>]} />
                          

                          т.к. в children могут быть несколько элементов.

                          И это ОЧЕНЬ удобно.
                          Есть еще вариант, например, как сделано в react-bootstrap модальное окно.

                          <div className="static-modal">
                              <Modal.Dialog>
                                <Modal.Header>
                                  <Modal.Title>Modal title</Modal.Title>
                                </Modal.Header>
                          
                                <Modal.Body>
                                  One fine body...
                                </Modal.Body>
                          
                                <Modal.Footer>
                                  <Button>Close</Button>
                                  <Button bsStyle="primary">Save changes</Button>
                                </Modal.Footer>
                          
                              </Modal.Dialog>
                            </div>
                          

                          Все эти Header, Footer, Dialog, это статические поля в классе Modal.
                          В методе Modal.render потом вручную фильтруются дети. Что-то наподобие const header = this.props.children.filter(child=> child.type === Modal.Header)

                          • taujavarob
                            /#9841928

                            Так и я говорю — обычный привычный вид XML кода (с тегами и атрибутами).

                          • vintage
                            /#9841932

                            Я согласен, что это удобно, но это даже близко не XML. И нет никакого смысла предпочитать этот синтаксис банальному:


                            class MyApp extends React.Component {
                                render() { return (
                                    new MyPanel({
                                        head:{
                                            new MyHeader({
                                                title:"My Tasks",
                                                closable: true
                                            })
                                        },
                                        body:{
                                            new MyTaskList({
                                                assignee:"me"
                                                status:"todo"
                                            })
                                        }
                                    })
                                ) }
                            }

                            • taujavarob
                              /#9841944

                              vintage >Я согласен, что это удобно, но это даже близко не XML.

                              Тут вы не правы вовсе, — что несколько странно не видеть XML:
                              https://facebook.github.io/react/blog/2016/09/28/our-first-50000-stars.html

                              «Since about 2010 Facebook has been using an extension of PHP called XHP, which enables engineers to create UIs using XML literals right inside their PHP code.

                              ...we created JSX by forking js-xml-literal, a side project by XHP creator Marcel Laverdet. JSX took its name from js-xml-literal, which Jordan modified to just be syntactic sugar for deeply nested function calls.»

                            • dema
                              /#9841960

                              Я согласен, в таких вырожденных случаях React.createElement будет, наверное, удобнее даже визуально. Но, когда это обычный html с минимумом кода, то jsx всё-таки приятнее.

                              • vintage
                                /#9841984

                                В том-то и дело, что при компонентной декомпозиции места для сырого html практически не остаётся.

                          • vintage
                            /#9841938

                            Вот в бутстрапе, да, сделали XML, но цена этому — "В методе Modal.render потом вручную фильтруются дети.". Предложите каждый компонент так костылять?


                            Ну и опять же, сравните с:


                            $my_staticModel $my_modal_dialog
                                title \Modal title
                                body / \One fine body...
                                foot /
                                    < closer $mol_clicker childs /
                                        < closeLabel @ \Close
                                    < saver $mol_clicker childs /
                                        < saveLabel @ \Save changes

                            • taujavarob
                              /#9841950

                              vintage >Предложите каждый компонент так костылять?

                              Есть отличный (не шучу) Ext.js

                              Там ООП реализовано а все 100% — там свыше 400 классов для всего(!)
                              Хотите наследуйтесь, перегружайтесь, миксируйте…

                              Ext.js был года как 3-4 назад очень даже популярен.

                              Но дело в том, что БЫЛ (хотя он и сейчас есть — 6-я версия), но в трендах Ext.js сошёл на нет.

                              Ибо был… не революционен! Имхо.
                              ;-)

                              • vintage
                                /#9841954 / +1

                                лучше бы шутили, ибо ExtJS — тот ещё bloatware. Именно это его и сгубило.

                            • dema
                              /#9841952

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

                              • vintage
                                /#9841956

                                Попробуйте рационализировать свою неприязнь :-)

                                • taujavarob
                                  /#9841966

                                  vintage 4 >Попробуйте рационализировать свою неприязнь :-)

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

                                  • vintage
                                    /#9841988

                                    Совершенство достигнуто не тогда, когда нечего добавить, а когда нечего убрать.

                        • babylon
                          /#9842058

                          Дмитрий, неужели это уже реально работает? Т.е. генерится движком, а не вашими умелыми руками. Просто реализовать скобочные теги это совсем неtreeвиально. Я искренне рад если у вас это получилось…

                          • vintage
                            /#9842224

                            Работает. Можете сами попробовать.


                            Что такое "скобочные теги"? Тут вообще нет никаких тегов — только создание компонент из других компонент, что в перспективе позволит рендерить хоть в OpenGL.

                            • babylon
                              /#9842336

                              {«имя тега»:[...]}

                              • vintage
                                /#9842356

                                А где вы видите у меня скобочные теги? Если вы о первом примере, то это JSX.

                        • indestructable
                          /#9842364

                          Это не то же самое. Т.к. в примере с реактом заголовок и тело панели — это, скорее всего, не просто содержимое панели, а может быть обернуто в теги, добавлены классы и т.д.

                          • vintage
                            /#9842384

                            Приведёте пример?

                            • indestructable
                              /#9843490

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


                              <div class="modal fade" tabindex="-1" role="dialog">
                                <div class="modal-dialog" role="document">
                                  <div class="modal-content">
                                    <div class="modal-header">
                                      <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                                      <h4 class="modal-title">My Tasks</h4>
                                    </div>
                                    <div class="modal-body">
                                            <ul>
                                                    <li>TODO: Item</li>
                                            </ul>
                                    </div>
                                    <div class="modal-footer">
                                    </div>
                                  </div><!-- /.modal-content -->
                                </div><!-- /.modal-dialog -->
                              </div><!-- /.modal -->
                              

                              Сорри, реализовывать компонент не стал, это пример результирующей разметки. Как видим, появилось много обвязки и дополнительных элементов. Плюс ХТМЛ для списка задач добавился в modal-body.

                              • vintage
                                /#9843656

                                Что, сложно реализовать компонент? ;-)


                                В реализации на view.tree просто наследуемся от $my_panel и добавляем чего не хватает:


                                $my_modal $mol_panel
                                
                                    attr *
                                        tabindex \-1
                                        role \dialog
                                
                                    head /
                                
                                        < titler $mol_viewer
                                            childs / < title 
                                        < closer $mol_clicker
                                            eventClick > eventClose null
                                            hint < closeHint @ \Close dialog
                                            childs < closeIcon $mol_icon_close

                                Стопочку тегов реализовывать не стал, ибо они лишние. А вот и использование:


                                $my_modal_demo $my_modal
                                
                                    title \My Tasks
                                
                                    body /
                                        < task1 $my_task_row title \Task #1
                                        < task2 $my_task_row title \Task #2
                                        < task3 $my_task_row title \Task #3

                                • taujavarob
                                  /#9843660 / +1

                                  >В реализации на view.tree просто наследуемся от $my_panel и добавляем чего не хватает:

                                  Странный новый дивный язык. — Зачем?

                                  • vintage
                                    /#9843674

                                    Затем, чтобы создание и использование компонент не вызывало боль.

                                    • taujavarob
                                      /#9843736

                                      >Затем, чтобы создание и использование компонент не вызывало боль.

                                      Но есть же язык Javascript! Там можно и наследоваться и добавить чего не хватает и перегрузить методы и прочая и прочая.

                                      Но взамен мы изобретаем НОВЫЙ язык. Зачем?

                                      • vintage
                                        /#9843770

                                        Затем, чтобы не писать километры кода.


                                            /// event * click > eventClick
                                            event() {
                                                return $mol_merge_dict( super.event() , {
                                                    "click" : ( ...diff : any[] )=> <any> this.eventClick(  ...diff ) ,
                                                } )
                                            }

                                            /// contenter $mol_viewer childs / < content
                                            @ $mol_prop()
                                            contenter() {
                                                const next = new $mol_viewer() 
                                                next.childs = () => [].concat( this.content() )
                                                return next
                                            }

                                        • justboris
                                          /#9843844 / +2

                                          Мой опыт мне говорит, что иногда лучше писать чуть больше кода, чем разгадывать клинопись из <,/,$,@ и т.д.

                                          • vintage
                                            /#9843862

                                            Лучше один раз освоить 6 операторов, чем писать 6 строчек вместо одной.


                                            < - односторонний биндинг
                                            > - двусторонний
                                            @ - локализуемая строка
                                            \ - сырые данные
                                            / - список
                                            * - словарь
                                            # - произвольный ключ
                                            $ - префикс имени компоненты

                                            • babylon
                                              /#9845248

                                              Дмитрий, эти обозначения еще где-то приняты?
                                              <=> вместо ">" не лучше?
                                              Я принял "<" за начало тега. Аааа-а!

                                              • vintage
                                                /#9845312

                                                Нет.


                                                Интуитивней, но набирать очень не удобно.


                                                Какие вы предложили бы обозначения для этих штук?

                                                • babylon
                                                  /#9845458 / -1

                                                  Для однопоточных данных:

                                                  to — указатель контента
                                                  from — указатель контейнера
                                                  parent — указатель на родительский контейнер
                                                  children — указатель детей.
                                                  override — указатель перекрывающего контента
                                                  по дефолту контейнер используется для композиции.

                                                  var — локализуемая строка, переменная
                                                  raw — сырые данные
                                                  [] — список, массив
                                                  {} — словарь, мап
                                                  : — произвольный ключ

                                                  pars — параметры
                                                  main — префикс имени компоненты
                                                  return — возврат
                                                  call — вызов/исполнение

                                                  Я по памяти пишу. Поэтому мог не всё вспомнить. Соряйте:)

                                                  • taujavarob
                                                    /#9846004

                                                    babylon >Я по памяти пишу. Поэтому мог не всё вспомнить. Соряйте:)

                                                    У вас много букв. ;-)

                                                    • babylon
                                                      /#9846420

                                                      Откройте Nodejs. Там еще больше. Тем не менее движок компактный двухпроходной. У меня суффиксов и префиксов раза в два больше, чем я написал. На всех значков не хватит по любому.Стандартными компиляторами они не обрабатываются.

                                                      • taujavarob
                                                        /#9846472

                                                        babylon > На всех значков не хватит по любому.

                                                        Unicodе большой. Хватит по любому всем.

                                                        • babylon
                                                          /#9846698

                                                          Ага, еще бы клавиатуру специальную для этого.

                                                          • taujavarob
                                                            /#9846726

                                                            babylon > Ага, еще бы клавиатуру специальную для этого.

                                                            Это идея для Kickstarter

                                        • indestructable
                                          /#9844268

                                          Какого типа contentchilds)? Есть ли возможность их обработать?

                                          • vintage
                                            /#9844544

                                            В данном случае childs — массив, а content — любого типа. Обработать в каком смысле?

                                            • indestructable
                                              /#9844700

                                              Обработать в каком смысле?

                                              Отфильтровать по типу элемента, по заданным свойствам, программно создать массив элементов и т.д.

                                              • vintage
                                                /#9844846

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

                                        • taujavarob
                                          /#9844872

                                          vintage >Затем, чтобы не писать километры кода.

                                          К этому стремятся все. :-)
                                          В языки программирования ПОСТОЯННО вводят новые конструкции позволяющие писать меньше кода. ;-)

                                          И, я согласен, что DSL язык можно ЗАТОЧИТЬ для конкретной области более точно («острее») чем использование универсального(более «широкого» чем DSL) языка программирования — Это мы практически видим и на примере Angular (со своими шаблонами и тегами) так и на примере React (со своим JSX).

                                          Но вот взлетит или нет этот «заточенный» DSL — этого никто не скажет. Имхо.

                                          • vintage
                                            /#9844948

                                            JSX и Angular же взлетели.

                                            • taujavarob
                                              /#9844988

                                              vintage >JSX и Angular же взлетели.

                                              Верно. Но это НЕ отменяет того, что — но вот ВЗЛЕТИТ ИЛИ НЕТ этот «заточенный» DSL — этого никто не скажет.

                                              А сколько НЕ взлетело то!

                                              • vintage
                                                /#9845296

                                                Поэтому нужно сложить руки и жрать либо один хайповый кактус, либо другой?

                                                • taujavarob
                                                  /#9845366

                                                  vintage >Поэтому нужно сложить руки и жрать либо один хайповый кактус, либо другой?

                                                  Нет, надо ускоряться. Имхо. ;-)

                                                  Если сейчас, бают, раз в день выходит новый js фреймворк, то надо бы каждые 4 часа, по крайней мере. ;-)

                                                  Я только хочу отметить — взлетит или нет не знает никто. Никто из людей.

                                                  И кто бы за js фреймворком ни стоял — это НЕ поможет — есть примеры, когда проваливались проекты фреймворков и языков и от MS и от Гугла.

                  • PFight77
                    /#9843696

                    То есть, Вы считаете, что в промышленной разработке все "настолько просто", что заботиться о читаемости кода не нужно?


                    Я соглашусь, что Реакт дает больше гибкости. Можно, например, вынести часть рендеринга в метод, и переопределить его в дочернем классе. Вопрос в том, как часто нужна такая гибкость? Все-таки, 80% веба это простой контент, без особых замороченных контролов.


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

                    • taujavarob
                      /#9843746

                      PFight77 >То есть, Вы считаете, что в промышленной разработке все «настолько просто», что заботиться о читаемости кода не нужно?

                      Я хочу сказать что код приводимый с целью быстрее ПОНЯТЬ суть должен отличаться от кода когда СУТЬ УЖЕ ПОНЯТА.

                      В продакшене СУТЬ УЖЕ ПОНЯТА постоянным(рутинным) практическим написанием кода.
                      Код продакшена НЕ предназначен для быстрого ПОНИМАНИЯ сути.
                      Код продакшена должен быть рутинным кодом.

                      PFight77 > Все-таки, 80% веба это простой контент, без особых замороченных контролов.

                      Это пока, но вэб меняется — он становиться сложнее. Разве не так?

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

                      Вы идеалист. ;-)

  21. Voronar
    /#9841974 / +1

    В ES6 ещё можно так делать:

    function Component(str, ...vals) {
      const props = vals[0];
      const children = vals[1];
      //...
    }
    
    function render() {
      const props = {};
      
      return (
        Component`${props}${
          Component`${props}${'nested'}`
        }`
      );
    }