Взгляд в прошлое и настоящее веб-приложений

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

История одностраничного веб-приложения

Вы хотите разработать одностраничное веб-приложение?

Если вы разработчик веб-сайтов, вы должны изменить свой менталитет.

Одностраничное веб-приложение похоже на настольное программное обеспечение. Он не обновляет страницу ни при одном клике. Он не может позволить вам нажать F5, если что-то не так.

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

Кто решает, когда эти актеры должны спать или просыпаться?

Бизнес-логика приложения.

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

Прошлое…

Ах, прошлое... Это было великолепно и прекрасно…
При разработке веб-приложений у вас было два основных подхода.

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

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

Итак, давайте поговорим о коде и фреймворках…

Одним из первых фреймворков, созданных с использованием этого подхода, является ExtJs, созданный Sencha.
Набор компонентов пользовательского интерфейса, с помощью которых можно создать интерфейс некоторых приложений за несколько минут. Это также поможет вам управлять жизненным циклом приложения.
Однако ExtJs не предоставляет архитектуру MVC.
Итак, давайте посмотрим, что будет дальше…

Другие фреймворки, использующие javascript в качестве основного действующего лица, — это Ember.js, Knockout.js, Backbone.js и множество менее используемых MVC или MVVM frameworks.
Я знаю, что мы говорим о прошлом, но я должен говорить об этих фреймворках в настоящем времени, потому что они все еще широко используются.

Эти технологии позволяют нам легко управлять маршрутизацией и контроллерами. Они поставляются с механизмами шаблонов, такими как Handlebars.js (от создателей Ember.js) для управления представлением, за исключением аналогичного Backbone.js. на ExtJs,нос архитектуройMV.
С помощью этого механизма шаблонов вы можете отображать некоторые представления и управлять привязкой данных в исполнительный способ. Они используют методы Javascript, такие как insertAdjacentHTML и innerHTML, которые лучше создают все объекты DOM.

Позвольте мне показать вам пример приложения Ember.js:

<!doctype html>
<html>
  <head>
    <script src='http://code.jquery.com/jquery-1.10.1.min.js'></script>
    <script src='https://cdn.pubnub.com/pubnub.js'></script>
    <script src='https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/2.0.0/handlebars.min.js'></script>
    <script src="http://builds.emberjs.com/tags/v1.9.0/ember.prod.js"></script>
    <script src='http://pubnub.github.io/pubnub-ember/lib/pubnub-ember.js'></script>
    <link href='//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css' rel='stylesheet'>
  </head>
  <body>
    <script data-template-name='application' type='text/x-handlebars'>
      <div class="container">
      <h4>Online Users</h4>
      <ul>
      {{#each user in users}}
         <li>{{user}}</li>
      {{/each}}
      </ul>
      <br />
      <h4>Chat History ({{messages.length}})</h4>
      <form>
         {{input type="text" value=new_message placeholder="Enter a message"}}
         <input type="submit" {{action publish}} />
      </form>
      <br />
      <div class="well">
      <ul>
      {{#each message in messages}}
         <li>{{message}}</li>
      {{/each}}
      </ul>
      </div>
      </div>
    </script>
    <script>
      window.Mini = Ember.Application.create();
      var user_id = "User " + Math.round(Math.random() * 1000);
      
      Mini.PubNub = PubNubEmber.extend({
        cfg: {
          subscribe_key: 'demo',
          publish_key: 'demo',
          uuid: user_id
        }
      });
      
      Mini.ApplicationController = Ember.Controller.extend({
        needs:['pubnub:main'],
        channel: 'The EmberJS Channel',
        new_message: '',
        user_id: user_id,
        // Ember Dynamic collection for messages list (live-updates the view)
        messages: Ember.ArrayProxy.create({ content: Ember.A(['Welcome to The EmberJS Channel']) }),
        // Ember Dynamic collection for user list (live-updates the view)
        users: Ember.ArrayProxy.create({ content: Ember.A([]) }),
      
        init: function() {
          var pn   = this.get('pubnub');   // PubNub service instance
          var chan = this.get('channel');  // channel name
          var self = this;                 // reference to 'this' for callbacks
      
          // Subscribe to the Channel
          pn.emSubscribe({ channel: chan });
      
          // Register for message events
          pn.on(pn.emMsgEv(chan), function(payload){
            self.get('messages').pushObject(payload.message);
          });
      
          // Register for presence events
          pn.on(pn.emPrsEv(chan), function(payload){
            self.get('users').set('content', pn.emListPresence(chan));
          });
          
          // Pre-Populate the user list (optional)
          pn.emHereNow({ channel: chan });
      
          // Populate message history (optional)
          pn.emHistory({
            channel: chan,
            count: 500
          });
        },
      
        actions: {
          // set up an Ember Action to publish a message
          publish: function() {
            this.get('pubnub').emPublish({
              channel: this.get('channel'),
              message: "[" + this.get('user_id') + "] " + this.get('new_message') 
            });
            this.set('new_message', '');
          }
        }
      });
    </script>
  </body>
</html>

Живой пример и пояснения по адресу: http://www.pubnub.com/blog/zero-emberjs-60-seconds-ember-made-easy/

Плюсы: это полноценные фреймворки. Быстрое и комфортное развитие.

Минусы: они используют механизмы шаблонов, которые отлично подходят для сокращения представлений из кода Javascript, но для смешивания компонентов и функций пользовательского интерфейса эти механизмы шаблонов (например, Mustache.js) используют вспомогательные функции, которые вы возвращаете html .
Таким образом, представления смешиваются с HTML и вспомогательными функциями.

Способ управления представлениями Backbone.js лучше подходит для проверки кода и управления, но, к сожалению, он многословен.

Еще одна тяжелая работа с этими платформами — управление контекстом выполнения и жизненным циклом приложения.

Помните историю с одностраничным веб-приложением.
Как я могу получить уведомление об удалении элемента из DOM и уничтожить все события привязки и наблюдатели?
Ребята из Ember.js сделали это. хорошая работа по решению подобных проблем (http://balinterdi.com/2014/02/12/making-an-emberjs-component-more-reusable.html).

Однако Ember.js не имеет четкой и четко определенной абстракцииИМХО.
Он управляет всеми программными компонентами семантическим образом, и вы упускаете контроль над тем, что происходит в жизненном цикле приложения. Это проблема оптимизации абстракции. Вы делаете меньше, фреймворк делает всю работу за вас, и вы теряете контроль над жизненным циклом. Однако Ember неплохо справляется с жизненным циклом, так что это совсем неплохо.

Также может быть очень сложно загружать внешние шаблоны, потому что вы должны определить их на своей HTML-странице.
Кто-то может сказать, что вы можете сделать это с помощью ajax, но фреймворки должны обеспечить лучшую абстракцию этого, вам не кажется?
В целом мне нравится Ember.js, потому что с его помощью можно создавать сложные приложения.

Второй подход: создайте свое приложение с помощью HTML и привяжите Javascript к элементам.

При таком подходе Javascript был привязан к html на событии DOMReady. Таким образом, элементы html объявили, какой контроллер должен быть привязан к ним через атрибут.

Одним из самых популярных фреймворков, работающих таким образом, является Angular.js.
Небольшой пример HTML-приложения Angular.js:

<!doctype html>
<html ng-app=”todoApp”>
 <head>
 <script src=”https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
 <script>
 angular.module(‘todoApp’, [])
 .controller(‘TodoListController’, function() {
 var todoList = this;
 todoList.todos = [
 {text:’learn angular’, done:true},
 {text:’build an angular app’, done:false}];
 
 todoList.addTodo = function() {
 todoList.todos.push({text:todoList.todoText, done:false});
 todoList.todoText = ‘’;
 };
 
 todoList.remaining = function() {
 var count = 0;
 angular.forEach(todoList.todos, function(todo) {
 count += todo.done ? 0 : 1;
 });
 return count;
 };
 
 todoList.archive = function() {
 var oldTodos = todoList.todos;
 todoList.todos = [];
 angular.forEach(oldTodos, function(todo) {
 if (!todo.done) todoList.todos.push(todo);
 });
 };
 });
 </script>
 <style>
 .done-true {
 text-decoration: line-through;
 color: grey;
 }
 </style>
 </head>
 <body>
 <h2>Todo</h2>
 <div ng-controller=”TodoListController as todoList”>
 <span>{{todoList.remaining()}} of {{todoList.todos.length}} remaining</span>
 [ <a href=”” ng-click=”todoList.archive()”>archive</a> ]
 <ul class=”unstyled”>
 <li ng-repeat=”todo in todoList.todos”>
 <input type=”checkbox” ng-model=”todo.done”>
 <span class=”done-{{todo.done}}”>{{todo.text}}</span>
 </li>
 </ul>
 <form ng-submit=”todoList.addTodo()”>
 <input type=”text” ng-model=”todoList.todoText” size=”30"
 placeholder=”add new todo here”>
 <input class=”btn-primary” type=”submit” value=”add”>
 </form>
 </div>
 </body>
</html>

http://jsbin.com/lepixisage/1/

Гораздо проще, не так ли?
Этот пример кода взят непосредственно с сайта Angular.js.

Опишем пошагово:

  • элемент html объявляет, какой «модуль» должен быть запущен с атрибутом ng-app
<html ng-app=”todoApp”>
  • сценарий создает модуль todoApp с TodoListController со всеми функциями, управляющими списком задач.
angular.module(‘todoApp’, [])
 .controller(‘TodoListController’, function() {
 var todoList = this;
 todoList.todos = [
 {text:’learn angular’, done:true},
 {text:’build an angular app’, done:false}];
 
 todoList.addTodo = function() {
 todoList.todos.push({text:todoList.todoText, done:false});
 todoList.todoText = ‘’;
 };
 
 todoList.remaining = function() {
 var count = 0;
 angular.forEach(todoList.todos, function(todo) {
 count += todo.done ? 0 : 1;
 });
 return count;
 };
 
 todoList.archive = function() {
 var oldTodos = todoList.todos;
 todoList.todos = [];
 angular.forEach(oldTodos, function(todo) {
 if (!todo.done) todoList.todos.push(todo);
 });
 };
 });
  • внутри тела есть div, который отображает все задачи и форму для добавления новых задач. Этот div имеет атрибут ng-controller, который связывает TodoListController с этим элементом с псевдонимом todoList.
    Существует много ng атрибут, используемый для определения, например, события щелчка, повторения html-кода для каждого элемента списка задач, отправки формы для добавления новой задачи, для привязки ввода к полю в контроллере $scope.
    Обратите внимание, что это не шаблон, который должен отображаться, а HTML-код страницы.
<div ng-controller=”TodoListController as todoList”>
 <span>{{todoList.remaining()}} of {{todoList.todos.length}} remaining</span>
 [ <a href=”” ng-click=”todoList.archive()”>archive</a> ]
 <ul class=”unstyled”>
 <li ng-repeat=”todo in todoList.todos”>
 <input type=”checkbox” ng-model=”todo.done”>
 <span class=”done-{{todo.done}}”>{{todo.text}}</span>
 </li>
 </ul>
 <form ng-submit=”todoList.addTodo()”>
 <input type=”text” ng-model=”todoList.todoText” size=”30"
 placeholder=”add new todo here”>
 <input class=”btn-primary” type=”submit” value=”add”>
 </form>
 </div>

Поэтому, когда дом готов, Angular вызывает его фазу начальной загрузки, которая связывает модуль и все его контроллеры.

Плюсы: Angular.js позволяет нам разрабатывать сложные функции с меньшим количеством кода, чем другие фреймворки. У него четкий жизненный цикл (не лучше, чем у Ember.js, но гораздо более интуитивно понятный ИМХО). Он хорошо интегрирован с другими инструментами, такими как Firebase или Parse, интегрирует REST-фреймворки, такие как Loopback, через автоматический генератор сервисов и все самые популярные библиотеки пользовательского интерфейса, такие как Twitter Bootstrap.

Минусы: то, что мне не нравится в Angular.js, — это двусторонняя система привязки данных (многим это не нравится) и многое другое — его концепция модульности. У вас нет отдельных модулей, а действительно наследование ООП.
Вы не можете использовать два модуля на одной странице, но вам нужно импортировать модуль в другой. Это означает, что все контроллеры, службы, фабрики и другие объекты, такие как конфигурация модуля, будут импортированы в другой модуль.

var app = angular.module('appModule',['userModule','UIModule','otherModule']);

Может быть сложно управлять именем объекта, конфликтами и контекстом выполнения, за что отвечают контроллеры.

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

Другой фреймворк, получивший большой успех среди разработчиков, — Polymer. Созданный Google, Polymer поставляется с полифиллом для технологии веб-компонентов.

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

<head>
 <link rel=“import” href=“fb-button.html”/>
</head>
<body>
 …
 <fb-button />
 …
</body>
  • Шаблон HTML5 и Shadow DOM: возможность создавать шаблон в HTML как тег, который браузер не отображает, то же самое, что и тег скрипта, который содержит HTML-код для шаблона Handlebars.js.
    С Shadow DOM вы можете создать шаблон с элементом content, который можно использовать для переопределения части HTML-кода компонента.

Пример компонента Simple Polymer, HTML + Javascript:

<polymer-element name="post-element"  attributes="">

  <template>

    <style>
      @host { :scope {display: block;} }
    </style>

    <span>I'm <b>post-element</b>. This is my Shadow DOM.</span>

  </template>

  <script>

    Polymer('post-element', {

      //applyAuthorStyles: true,

      //resetStyleInheritance: true,

      created: function() { },

      enteredView: function() { },

      leftView: function() { },

      attributeChanged: function(attrName, oldVal, newVal) { }

    });

  </script>

</polymer-element>

Позвольте мне показать вам пример с Shadow DOM:

<!-- define the Polymer Component -->
<polymer-element name="my-custom-element" noscript>
  <!-- define the Shadow DOM -->
  <template>
    <span>People say: </span>
      <content select="q"></content>
    <footer>sometimes</footer>
  </template>
</polymer-element>
...
<!-- define light DOM -->
<my-custom-element>
  <q>Hello World</q>
</my-custom-element>

Таким образом, с помощью Polymer мы можем создавать множество компонентов со своими собственными CSS, Javascript и HTML. Очевидно, что он обеспечивает двустороннюю привязку данных и поставляется с набором четко определенных компонентов пользовательского интерфейса, написанных в соответствии с шаблоном пользовательского интерфейса Material Design от Google.

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

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

Позвольте мне составить список последних проблем, вот что важно:

  • двусторонняя привязка данных: да, это проблема… http://larseidnes.com/2014/11/05/angularjs-the-bad-parts/
  • непонятный жизненный цикл приложения: как я уже говорил выше, Ember — единственная платформа, которая заботится обо всем жизненном цикле приложения (запуск приложения —> обработка маршрутов —> рендеринг представления —> взаимодействие с пользователем —> события обработка —> предоставление данных и управление ими).
    Когда вам нужно управлять всеми программными компонентами и контекстом и контролировать их, отсутствие возможности взаимодействовать с жизненным циклом приложения может быть ограничением.
  • жесткое повторное использование и упаковка: мы хотим использовать некоторые компоненты, написанные другими. Для этого нам нужно установить соответствующие JS и CSS и использовать их в HTML. Это может занять некоторое время. Должен быть оптимизирован.
  • компиляция активов и библиотек: мы не заставляем браузер загружать все отдельные файлы, такие как модели JS, контроллеры, представления, библиотеки, таблицы стилей CSS каждого отдельного плагина или компонентов пользовательского интерфейса.

А как насчет настоящего в моем понимании? Давайте продолжим.

Настоящее!!

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

Начните с инструментов…

Упаковка

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

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

Преимущества: нам не нужно самостоятельно скачивать все библиотеки, которые мы хотим. Менеджер пакетов может сделать это за нас. Кроме того, если у нас есть много зависимостей, указанных в настройках менеджера пакетов для нашего проекта, такое программное обеспечение может управлять ими за нас (файл настроек может быть в формате XML или JSON, в зависимости от используемого менеджера пакетов). Если у этих библиотек есть другие зависимости, менеджер пакетов загрузит их все и так далее.

Позвольте мне привести несколько примеров Реестр NPM (менеджер пакетов узла)..

Проект А с собственным репозиторием.
Зависимости: jQuery, Backbone, Hammer

Ниже приведен пример файла package.json для проекта A. Внутри него мы определяем все зависимости, необходимые для этого проекта, поэтому npm их загрузит.

{
 “name”: “project-a”,
 “version”: “0.0.1”,
 “description”: “A project made by My Company Inc”,
 “author”: “Your Name <[email protected]>”,
 “repository”: {
    “type”: “git”,
    “url”: “https://github.com/my-company/project-a"
 },
 “dependencies”: {
    “jquery”: “*”,
    “backbone”: “*”,
    “hammerjs”: “*”
 },
 “private”: true
}

Тим хочет реализовать некоторые новые функции в проекте A.
Тим должен клонировать репозиторий:

git clone https://github.com/my-company/project-a

Теперь запустите команду cd по пути, содержащему файл package.json, и запустите команду установки (требуются установленные npm и node.js).

npm install

Npm начнет скачивать все необходимые библиотеки со своими зависимостями.
Вот и все!!! Теперь Тим может писать свой код без ошибок.

Другие менеджеры пакетов:

Компиляция

Иногда вы хотите объединить и минимизировать все файлы Javascript в один раз.

Это может быть полезно для производительности и позволит вам включить только один файл javascript вместо всех необходимых.

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

Компиляция файлов CSS и Javascript с помощью Task Runner

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

Предположим, нам нужно создать файлы Javascript и Css, объединив и минимизировав их. Также мы должны объединить все файлы svg в один.
Запуск задач может сделать все эти операции за вас.

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

Некоторые из самых популярных веб-бегунов задач:

  • ворчание
  • глоток
  • кекс

Чтобы вы могли узнать больше, я хочу дать ссылку на сравнение:
http://blog.cozycloud.cc/technic/2014/06/18/task-runners-comparison/

Компиляция файлов CSS и Javascript с помощью Webpack

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

Используя Webpack, вы можете разрабатывать все свои веб-приложения по шаблону AMD. Затем Webpack скомпилирует все ваши файлы Javascript, CSS и ресурсов, чтобы легко импортировать их в браузер.

Webpack использует множество плагинов, собственных или сторонних разработчиков.
Наиболее полезными плагинами являются babel (компиляция ES6/7) и less/sass (компилировать less и sass в css, требуя его от Javascript) .

Узнайте больше и посмотрите несколько примеров:

Похож на Webpack и очень популярен RequireJS для компиляции AMD. Я должен процитировать это, это потрясающе !!

Компиляция Javascript для узла в качестве глобального объекта браузера и архитектуры AMD с помощью Browserify

Иногда мы хотим разработать библиотеку, которую можно использовать как в Node.js, так и в архитектурах AMD, таких как RequireJS/CommonJS, или в качестве глобального объекта браузера.

Это может быть очень сложно, поэтому родился стандарт под названием UMD (Universal Module Definition).

Следуя указаниям этого стандарта, мы можем достичь этой цели.
К сожалению, это не лучшее решение для читаемости кода.

Используя Browserify, мы можем разработать наши библиотеки в шаблоне модуля узла, а затем преобразовать код для AMD или глобального объекта браузера.

Выучить больше:

Итак, теперь у нас есть возможность зарегистрировать наши библиотеки в диспетчере пакетов, который управляет всеми зависимостями для нас, создает библиотеки для Node, AMD и браузера, а также компилирует все активы, файлы Javascript и CSS с помощью Task Runner или Webpack.

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

React и Flux для создания веб-приложений

Краткое введение в React и Flux.

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

Список его особенностей:

  • Нет механизма шаблонов: React не имеет механизма шаблонов. Это позволило нам создать элемент DOM с помощью JSX, непосредственно в коде Javascript компонентов. Это дает нам возможность иметь представления и поведение в одном месте.
  • Виртуальный DOM: интеллектуальный метод, повышающий производительность изменений DOM. React обновляет представления каждый раз, когда обновляются данные. Для этого весь DOM перерисовывается. Затем React выполняет сравнение с фактическим DOM и новым сгенерированным DOM, поэтому он может применять только необходимые изменения. Проблема возникает, когда он генерирует новый DOM после изменения данных; от создания до рендеринга объект DOM заполняется множеством атрибутов, которые на самом деле не нужны для сравнения и генерируют много памяти. Это снижает производительность. Виртуальный DOM можно использовать вместо реальных объектов DOM. Он генерирует только необходимые атрибуты, необходимые для представления элемента. Таким образом, diff может быть более производительным. Узнайте больше о React DOM diff и сложности его алгоритма.
  • Делегирование событий: React управляет событиями DOM с помощью внутренней системы EventPlugins, которая позволяет нам использовать как простые события, такие как щелчок / mouseEnter, так и сложные события, такие как копирование / вырезание / прокрутка и т. д. Подробнее: Делегирование событий. », Система React Event.

Пример компонента React

// use ReactCSSTransitionGroup in order to manage transitions
var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
// menu component
var Menu = React.createClass({
 getInitialState: function( ) {
  return {
   selectedItem: 0
  };
 },
 render: function(){
  return (
   <nav className=”menu”>
   {this.props.menuItems.map(function( menuItem, i ){
     var selectedClass = “”; 
     if( i == this.state.selectedItem ) {
      selectedClass = “ selected”;
     }
     var className = “menu__item” + selectedClass;
     return <a
             key={i}
             href={menuItem.href}
             className={className}
             title={menuItem.title}
             onClick={this.handleMenuItemClick.bind(null, i)}>     
               {menuItem.label}
             </a>;
   }.bind(this))}
   </nav>
  );
 },
 
 componentDidMount: function( ) {
    this.props.onSelected( this.state.selectedItem );
 },
 
 handleMenuItemClick: function( i, e ) {
   if( !this.props.onSelect ) {
    this.setMenuItem( i );
    return;
   }
 
   this.props.onSelect( i, this.setMenuItem.bind( this, i ) );
 },
 
 setMenuItem: function( index ) {
   this.setState({
    selectedItem: index
   }, function(){
    this.props.onSelected( index );
   }.bind(this));
 }
});
// content list component
var ContentList = React.createClass({
 render: function( ) {
   var childs = React.Children.map(
     this.props.children,
     function( child, i ){
       if( i == this.props.visible ) {
        return (
         <div key={i}>
          {child}
         </div>
        );
       }
     }.bind(this)
   );
 
   return (
    <div className=”content-container”>
     <ReactCSSTransitionGroup
     transitionName=”fade”
     transitionAppear={true}>
       {childs}
     </ReactCSSTransitionGroup>
    </div>
   );
 }
});
// content component
var Content = React.createClass({
 render: function( ) {
   return (
     <div className=”content”>
      {this.props.children}
     </div>
   );
 }
});
// application
var Application = React.createClass({
 getInitialState: function(){
    var self = this;
    var state = {
     menuProps: {
      menuItems: [
       {
        href: “#a”,
        title: “A”,
        label: “A Item”
       },
       {
        href: “#b”,
        title: “B”,
        label: “B Item”
       },
       {
        href: “#c”,
        title: “C”,
        label: “C Item”
       }
      ],
      onSelected: function( i ) {
       self.state.selectedContent = i;
       self.setState( self.state );
      }
     },
     selectedContent: 0
    };
 
    return state;
 },
 render: function(){
   return (
    <div>
     <Menu {…this.state.menuProps} />
     <ContentList visible={this.state.selectedContent}>
      <Content>
       <h3>Content for A</h3>
 
       <p>
        Lorem Ipsum dolor sit amen…
       </p>
 
       <img src=”http://placehold.it/400x200" />
      </Content>
      <Content>
       Content for B element
      </Content>
      <Content>
       Content for C element
      </Content>
     </ContentList>
    </div>
   );
 }
});
React.render(<Application />, document.body);


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

Путь Flux

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

Непосредственно из обзора Flux:

Изначально мы намеревались корректно работать с производными данными: например, мы хотели показать количество непрочитанных цепочек сообщений, в то время как другое представление показывало список цепочек с выделенными непрочитанными. С этим было сложно справиться с помощью MVC — пометка одного потока как прочитанного обновила бы модель потока, а затем также необходимо обновить модель счетчика непрочитанных сообщений. Эти зависимости и каскадные обновления часто возникают в большом приложении MVC, что приводит к запутанному переплетению потока данных и непредсказуемым результатам.

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

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

Узнайте больше об архитектуре приложений Flux.

Некоторые полезные ресурсы:

Вывод

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

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

Однако эти технологии могут сделать нас намного умнее в разработке.

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

Очевидно, что эти новейшие технологии легче тестировать и повысить производительность вашего приложения.

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

Спасибо за внимание,
до свидания и удачи!