Довольно часто приходится слышать, что 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
    28.09.2016 15:33

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


    1. nazarpc
      28.09.2016 16:08

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


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

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


      1. justboris
        28.09.2016 17:52
        +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.


        1. nazarpc
          28.09.2016 18:21
          +9

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


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


          1. DGolubets
            28.09.2016 18:51
            -1

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


            1. nazarpc
              28.09.2016 18:56
              +2

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


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


          1. wert_lex
            28.09.2016 18:51
            +3

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


            1. nazarpc
              28.09.2016 19:03
              +1

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


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


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


          1. justboris
            28.09.2016 18:57

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


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


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


            1. nazarpc
              28.09.2016 19:09
              +1

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


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


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


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


              1. i360u
                29.09.2016 06:23

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


                1. nazarpc
                  29.09.2016 06:28

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


                  1. i360u
                    29.09.2016 07:35

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

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


                    1. nuit
                      29.09.2016 08:28

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

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


                      1. i360u
                        29.09.2016 08:52

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


                        1. nuit
                          29.09.2016 09:19

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


                          1. i360u
                            29.09.2016 10:04

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


                            1. nuit
                              29.09.2016 10:18

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

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


                              1. i360u
                                29.09.2016 10:29

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


                                1. nuit
                                  29.09.2016 10:49

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

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

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


                                  1. i360u
                                    29.09.2016 11:00

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

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


                                    1. nuit
                                      29.09.2016 11:05

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


                                      1. i360u
                                        29.09.2016 11:16

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


                                        1. nuit
                                          29.09.2016 11:22
                                          +1

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

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

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


                                          1. i360u
                                            29.09.2016 11:53

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


                                            1. nuit
                                              29.09.2016 12:03

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


                                            1. indestructable
                                              29.09.2016 13:40

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


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


                                              1. nuit
                                                29.09.2016 13:47

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

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


                                            1. G-M-A-X
                                              29.09.2016 14:05
                                              -1

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

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


                                              1. nuit
                                                29.09.2016 14:07

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


                              1. arvitaly
                                29.09.2016 10:30

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


            1. i360u
              29.09.2016 06:13

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


          1. dema
            04.10.2016 22:13

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


            1. gearbox
              05.10.2016 16:33

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


              1. justboris
                05.10.2016 16:51

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


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


                1. gearbox
                  05.10.2016 17:11

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

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

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


                  1. justboris
                    05.10.2016 17:38

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


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


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


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


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


                    1. vintage
                      05.10.2016 19:27

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


                      1. dema
                        05.10.2016 21:28

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


                        1. vintage
                          05.10.2016 22:03

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


                      1. justboris
                        05.10.2016 22:45

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


                    1. gearbox
                      05.10.2016 19:30

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

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


  1. jMas
    28.09.2016 15:42

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


  1. nazarpc
    28.09.2016 16:01

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


    1. justboris
      28.09.2016 16:16
      +3

      Добрый день!


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


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


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


      [[if(isOverLimit, warningText)]]

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


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


      1. k12th
        28.09.2016 16:29
        -1

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

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


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

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


        1. MorozoW
          28.09.2016 18:50

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


          1. reactoranime
            29.09.2016 12:11

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


      1. nazarpc
        28.09.2016 16:33

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


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


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


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


  1. k12th
    28.09.2016 16:03
    +1

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


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


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


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


    1. gearbox
      28.09.2016 16:14
      -3

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


    1. justboris
      28.09.2016 16:28
      +1

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


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


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


      1. k12th
        28.09.2016 16:32

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


      1. nazarpc
        28.09.2016 16:37

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


        1. gibson_dev
          28.09.2016 19:57

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


          1. nazarpc
            28.09.2016 20:08
            +1

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


            1. gibson_dev
              28.09.2016 20:13
              +2

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


    1. Laney1
      28.09.2016 17:07
      +2

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

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


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


    1. SPAHI4
      29.09.2016 10:46

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


  1. gearbox
    28.09.2016 16:03
    +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);
    


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


    1. justboris
      28.09.2016 16:04

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


      1. gearbox
        28.09.2016 16:10

        обновил


    1. TheShock
      28.09.2016 16:15

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

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


      1. gearbox
        28.09.2016 16:23
        +1

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


        1. taujavarob
          28.09.2016 23:18

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

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


    1. serf
      29.09.2016 02:46

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


      1. gearbox
        29.09.2016 10:04

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


        1. serf
          29.09.2016 11:58

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


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


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


          1. gearbox
            29.09.2016 12:15

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

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

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


            1. serf
              29.09.2016 12:16

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

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


              1. gearbox
                29.09.2016 12:36

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


          1. justboris
            29.09.2016 12:29

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


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


  1. G-M-A-X
    28.09.2016 16:37

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

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

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


    1. justboris
      28.09.2016 18:07
      +1

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


      1. G-M-A-X
        28.09.2016 22:57
        -2

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

        Зачем?

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

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

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


        1. taujavarob
          28.09.2016 23:24
          -1

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

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


  1. RubaXa
    28.09.2016 17:10
    +1

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


    1. justboris
      28.09.2016 18:01

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


      1. RubaXa
        28.09.2016 18:09
        +1

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


    1. justboris
      28.09.2016 18:02

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


      1. RubaXa
        28.09.2016 18:10

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


      1. Kain_Haart
        28.09.2016 22:06

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


        1. VasilioRuzanni
          29.09.2016 14:23

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


          1. Kain_Haart
            29.09.2016 18:58

            o_O


    1. babylon
      05.10.2016 12:36

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


  1. zapolnoch
    28.09.2016 18:00
    +5

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


    1. justboris
      28.09.2016 18:04

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


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



  1. vintage
    28.09.2016 21:26
    +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"
    }

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


    1. G-M-A-X
      28.09.2016 23:05

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


    1. domix32
      28.09.2016 23:09

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


  1. jakobz
    29.09.2016 00:13
    -3

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

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

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

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

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

    JSX — в топку.


    1. justboris
      29.09.2016 10:54

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


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


      1. jakobz
        29.09.2016 12:02

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

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


    1. dema
      04.10.2016 22:27

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


      1. jakobz
        04.10.2016 22:47

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


        1. dema
          04.10.2016 23:13

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


          1. justboris
            05.10.2016 11:23

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


            <div {...props} /> 

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


            1. taujavarob
              05.10.2016 15:45

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

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


              1. justboris
                05.10.2016 15:59

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


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

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

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


          1. jakobz
            08.10.2016 15:41

            Делая так:

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


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

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


  1. indestructable
    29.09.2016 00:18
    +2

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


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


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


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


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

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


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


    1. jMas
      29.09.2016 02:40

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


    1. justboris
      29.09.2016 11:01

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


      <div class="test" />

      станет таким


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

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


      1. indestructable
        29.09.2016 13:42

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


        1. justboris
          29.09.2016 15:44

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


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


    1. taujavarob
      29.09.2016 14:55

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

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


    1. PFight77
      05.10.2016 22:08

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


  1. serf
    29.09.2016 02:40

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

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


    1. indestructable
      29.09.2016 09:14
      +1

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


      1. serf
        29.09.2016 11:44
        +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} (зависимости) линкуются в отдельное поле объекта.


        1. indestructable
          29.09.2016 13:43

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


          1. serf
            29.09.2016 14:12

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


            1. serf
              29.09.2016 14:17
              +1

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


  1. sd_baron
    29.09.2016 11:01

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

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


    1. justboris
      29.09.2016 11:05

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


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


  1. serf
    29.09.2016 12:22

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


    1. gearbox
      29.09.2016 12:38

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


      1. serf
        29.09.2016 12:40

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


        1. justboris
          29.09.2016 12:48

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


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


  1. Asgator
    29.09.2016 12:42

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


    1. taujavarob
      29.09.2016 15:05

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


  1. indestructable
    29.09.2016 13:56
    +1

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


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


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


    1. G-M-A-X
      29.09.2016 14:58
      -1

      Приехали.

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


      1. indestructable
        29.09.2016 18:32

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


        1. taujavarob
          29.09.2016 18:49

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

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


  1. serf
    29.09.2016 15:06

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

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


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


    1. nuit
      29.09.2016 15:12
      +1

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

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

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

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


      1. serf
        29.09.2016 15:14

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


        1. nuit
          29.09.2016 15:15
          +1

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


          1. serf
            29.09.2016 15:17

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


            1. nuit
              29.09.2016 15:20

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

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


              1. serf
                29.09.2016 15:27
                -1

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

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


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


                1. nuit
                  29.09.2016 15:40
                  +1

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

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

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


                  1. serf
                    29.09.2016 15:45

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


                    1. nuit
                      29.09.2016 15:50

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


                      1. serf
                        29.09.2016 15:52
                        -1

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


                        1. taujavarob
                          29.09.2016 19:01

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

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


                          1. serf
                            29.09.2016 19:05

                            1. taujavarob
                              29.09.2016 19:08

                              Я читал это.

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

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

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

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


    1. indestructable
      29.09.2016 18:37
      +1

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


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


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

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


  1. Finesse
    30.09.2016 03:55

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


    1. vintage
      30.09.2016 10:28

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


      1. indestructable
        30.09.2016 10:50

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


        1. taujavarob
          30.09.2016 11:18

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

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


        1. justboris
          30.09.2016 11:32

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


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


          1. indestructable
            03.10.2016 10:08

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


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


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

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


        1. vintage
          30.09.2016 12:23

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


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


          1. indestructable
            03.10.2016 11:03

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


  1. taujavarob
    30.09.2016 11:10

    del


  1. PFight77
    30.09.2016 19:18

    Основная беда 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 в реактовском компоненте — не так просто.


    1. justboris
      30.09.2016 20:21
      +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 полностью? Вы работаете на своем уровне абстракции, дочерние компоненты отдельно, на их реализацию можно посотреть потом, если захочется


      1. taujavarob
        30.09.2016 21:02

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

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

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

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

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


      1. taujavarob
        30.09.2016 21:08

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


        1. justboris
          30.09.2016 22:06

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


      1. PFight77
        30.09.2016 21:45
        +1

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


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

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


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


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


        1. indestructable
          03.10.2016 11:27

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


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

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


        1. taujavarob
          03.10.2016 15:02
          +1

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

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

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


          1. PFight77
            03.10.2016 20:14

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


            1. taujavarob
              03.10.2016 20:25

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

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


              1. PFight77
                03.10.2016 20:36
                +1

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


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


                1. taujavarob
                  03.10.2016 20:45

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

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


                1. taujavarob
                  04.10.2016 15:59
                  +1

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

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

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

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

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

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

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


                  1. vintage
                    04.10.2016 21:37

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


                    1. taujavarob
                      04.10.2016 21:57

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

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

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

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


                      1. vintage
                        04.10.2016 22:26

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


                        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


                        1. taujavarob
                          04.10.2016 22:35

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

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


                          1. vintage
                            04.10.2016 22:43

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


                        1. dema
                          04.10.2016 22:52

                          Опять же, в примере с 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)


                          1. taujavarob
                            04.10.2016 22:59

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


                          1. vintage
                            04.10.2016 23:02

                            Я согласен, что это удобно, но это даже близко не 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"
                                            })
                                        }
                                    })
                                ) }
                            }


                            1. taujavarob
                              04.10.2016 23:10

                              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.»


                            1. dema
                              04.10.2016 23:26

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


                              1. vintage
                                04.10.2016 23:53

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


                          1. vintage
                            04.10.2016 23:06

                            Вот в бутстрапе, да, сделали 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


                            1. taujavarob
                              04.10.2016 23:16

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

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

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

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

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

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


                              1. vintage
                                04.10.2016 23:18
                                +1

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


                            1. dema
                              04.10.2016 23:17

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


                              1. vintage
                                04.10.2016 23:19

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


                                1. taujavarob
                                  04.10.2016 23:27

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

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


                                  1. vintage
                                    04.10.2016 23:55

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


                        1. babylon
                          05.10.2016 03:50

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


                          1. vintage
                            05.10.2016 09:15

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


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


                            1. babylon
                              05.10.2016 10:43

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


                              1. vintage
                                05.10.2016 10:54

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


                        1. indestructable
                          05.10.2016 10:57

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


                          1. vintage
                            05.10.2016 11:08

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


                            1. indestructable
                              05.10.2016 20:10

                              Попробую. Панель, в общем-то, довольной простой контрол, особенно придумывать нечего, но допустим, что мы хотим реализовать 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.


                              1. vintage
                                05.10.2016 21:58

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


                                В реализации на 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


                                1. taujavarob
                                  05.10.2016 22:01
                                  +1

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

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


                                  1. vintage
                                    05.10.2016 22:04

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


                                    1. taujavarob
                                      05.10.2016 22:45

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

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

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


                                      1. vintage
                                        05.10.2016 23:09

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


                                            /// 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
                                            }


                                        1. justboris
                                          06.10.2016 00:29
                                          +2

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


                                          1. vintage
                                            06.10.2016 00:50

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


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


                                            1. babylon
                                              06.10.2016 20:12

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


                                              1. vintage
                                                06.10.2016 20:45

                                                Нет.


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


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


                                                1. babylon
                                                  06.10.2016 22:35
                                                  -1

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

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

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

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

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


                                                  1. taujavarob
                                                    07.10.2016 09:44

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

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


                                                    1. babylon
                                                      07.10.2016 12:46

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


                                                      1. taujavarob
                                                        07.10.2016 12:56

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

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


                                                        1. babylon
                                                          07.10.2016 14:12

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


                                                          1. taujavarob
                                                            07.10.2016 14:29

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

                                                            Это идея для Kickstarter


                                                            1. babylon
                                                              07.10.2016 15:15

                                                              Дарю:)


                                        1. indestructable
                                          06.10.2016 10:56

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


                                          1. vintage
                                            06.10.2016 13:35

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


                                            1. indestructable
                                              06.10.2016 14:49

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

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


                                              1. vintage
                                                06.10.2016 16:09

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


                                        1. taujavarob
                                          06.10.2016 16:18

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

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

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

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


                                          1. vintage
                                            06.10.2016 16:52

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


                                            1. taujavarob
                                              06.10.2016 17:15

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

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

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


                                              1. vintage
                                                06.10.2016 20:37

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


                                                1. taujavarob
                                                  06.10.2016 21:22

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

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

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

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

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


                  1. PFight77
                    05.10.2016 22:17

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


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


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


                    1. taujavarob
                      05.10.2016 22:52

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

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

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

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

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

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

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


  1. Voronar
    04.10.2016 23:43
    +1

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

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