ReactJS: відмова від JSX зі збереженням зручності

ReactJS - це Javascript бібліотека для розробки веб-компонентів на основі віртуального DOM. ReactJS став вже досить популярний за той рік, як його випустила у світ компанія Facebook. Найближчим часом можна очікувати інтересу до цієї бібліотеки з боку ще більшої кількості компаній, тому що ReactJS дозволяє створювати надійні, продуктивні інтерфейси швидко.


Особливістю ReactJS є використання суміші HTML і Javascript для більшої читаності, наприклад:

render: function(){
      return <div>
        <div class=""clicker"" onMouseDown={this.handleMouseDown}>
          Give me the message!
</div>
        <div class=""message"">Message conveyed
          <span class=""count"">{this.state.count}</span> time(s)</div>
      </div>
      ;
    }

Ця мова називається JSX і перед її використанням у браузері спеціальна утиліта конвертує все в простий Javascript. Результат виходить такий:

render: function(){
  return React.DOM.div(null,
   React.DOM.div( {className:""clicker"", onMouseDown:this.handleMouseDown},
 Give me the message! ""   ),
   React.DOM.div( {className:""message""}, ""Message conveyed "",    React.DOM.span( {className:""count""}, this.state.count), "" time(s)"")
  )
  ;
 }

Можна не використовувати JSX і відразу писати на Javascript, але цей підхід більш трудомісткий і менш читабельний. З іншого боку, використання JSX накладає ряд вимог, які небажані, як те:

* використання додаткового редактора для розмітки JSX

* Використання додаткової утиліти для прекомпіляції JSX

* відмова від використання TypeScript

Відмова від TypeScript для мене неприйнятна, тому народилася така ідея: поліпшити читабельність за рахунок застосування зручної об'єктної структури Javascript і потім генерувати код React.DOM, знову на Javascript, взагалі без JSX. Вийшло так:

render: function () {
        var dom = [
          {
            tag: React.DOM.div,
            props: {
              className: ""class1"",
              onClick: this.handleClick
           },
           content: ""Hello "" + this.state.value
          },
          {
            tag: React.DOM.span,
            props: { },
            dom: [
              {
                tag: React.DOM.span,
                props: { className: ""class2"" },
                content: ""Hello "" + this.state.value
              }
            ]
          }
        ];
return parse(dom);
      }

Таким чином, створюється структура на основі масиву об'єктів, кожен з яких містить 3 властивості: tag, props і dom (якщо є вкладені об'єкти) або content (якщо цей об'єкт листовий). Функція, яка створює код для ReactJS така:

function parse(dom, inner) {
      var items = [];
for (var el in dom) {
        if (dom[el].dom) {
          items.push(dom[el].tag(dom[el].props, parse(dom[el].dom, inner || true)));
        } else {
          items.push(dom[el].tag(dom[el].props, dom[el].content));
        }
      }
      if (inner) {
        return items.length == 1 ? items[0] : items;
      } else {
        return items.length == 1 ? items[0] : React.DOM.section(null, items);
      }
    }

За результатами підхід виявився дуже зручним. Помітних втрат при відмальовуванні не виявлено, але не виключаю, що на складних інтерфейсах все-таки доведеться створювати DOM на основі примітивів React. У будь-якому випадку, цей крок оптимізації можна буде виконати на заключній стадії, після утряски власне компонентів.