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

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

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

Если вы спросите людей, вы, как правило, получите самые разные ответы, включая такие вещи, как сокращение кода, поддержание чистоты структуры, многоразовые элементы и т. Д. Но на самом деле это побочные эффекты. Фактическая цель проста. Они должны отображать состояние приложения в DOM.

Что это означает, наиболее наглядно демонстрируется путем демонстрации обратного, и лучший способ сделать это - показать некоторый jQuery.

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

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

<div>
    <span class="btn btn-primary toggle-button">Pigs</span>
    <span class="btn btn-primary toggle-button">Sheep</span>
    <span class="btn btn-primary toggle-button">Wolves</span>
</div>

<script>
$('.toggle-button').click(function(){
  $('.toggle-button').removeClass('active');
  $(this).addClass('active');
});
</script>

Здесь есть проблемы. Не элегантно, но служит. Во-первых, в .toggle-button нет реального смысла. Это совершенно произвольно. Связан ли с этим стиль? Может быть? Может быть нет? Удаление класса стиля изменит поведение - не идеально. Действительно ли это правильный выбор? Неужели для этого нужны занятия? Стоило ли использовать идентификаторы? Мы могли бы использовать атрибуты данных, но тогда мы тоже засоряем разметку ими.

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

let animalSelected = $('.toggle-button.active').html(); 

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

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

<input type="hidden" name="animal" id="animal" value="">

И в нашем событии javascript мы можем добавить следующее, чтобы получить значение животного.

$('#animal').val($(this).html());

Это немного улучшает обработку интерфейса. Если под «лучше» вы имеете в виду «немного хуже». Хотя мы исправили одну проблему, мы создали еще более серьезную. Для начала, здесь есть разметка, которая не может служить никакой реальной цели, кроме как корзина для числа. Но есть более глубокая проблема.

Допустим, у нас есть где-то еще одна функция, которая устанавливает животное - мы получили эти данные, например, из запроса Ajax, или они были загружены как часть редактирования. Значение скрытого ввода правильное, но ни одно из животных не отображается выбранным. Состояние вашего приложения сейчас в дерьме. Чтобы использовать технический термин.

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

Давайте посмотрим на эквивалентный компонент React. То же самое применимо к любой подобной платформе (Ember, Angular и т. Д.) Или библиотеке (Vue), но React предоставляет простой способ продемонстрировать на автономном примере.

export default class AnimalSelector extends component {
  constructor(){
    this.state = {
      animals: ['Pigs', 'Sheep', 'Wolves'],
      selectedAnimal: null
    }
  }
  selectAnimal(selectedAnimal){
    this.state({selectedAnimal});
  }
  animalButton(animal){
    const activeClass = this.state.selectedAnimal === animal 
        ? 'active' 
        : '';
    return (<span 
      class={`btn btn-primary ${activeClass}`} 
      onClick={() => this.selectAnimal(animal)}>
        {animal}
    </span>)
  }
  render(){
    return <div>
      {this.state.animals.map(animal => this.animalButton(animal))}
    </div>
  }
}

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

Структура компонента React относительно проста - данные, которые создают интерфейс, хранятся в свойстве состояния. Отрисовка компонента (с render()) использует это состояние для принятия решений о том, как визуализировать элементы. Изменения этого состояния (все сделано с использованием this.setState) вызывают повторный рендеринг компонента, переделывая все предыдущие решения по макету. Этот «единый источник истины» о том, как объект должен выглядеть и вести себя, имеет решающее значение и то, чего нам не хватало в наших примерах jQuery. По сути, все эти элементы «привязаны» к государству.

Дело в том, что ни одна из потенциальных проблем, перечисленных в приведенном выше примере jQuery, не возникнет в этом примере React. Мы не пытались их избежать. По сути, это не проблемы. И они не станут проблемами.

Это не означает, что проблем не возникает. На самом деле управление этим состоянием должным образом и последовательно, и особенно совместное использование его между компонентами, может быть трудным. Эту проблему так элегантно решают такие инструменты, как Redux и Ember Data.

Архитектура приложения - сложная вещь, и привязка представлений - лишь малая ее часть. Это то, что фреймворки JavaScript делают удивительно похожими способами, несмотря на различный синтаксис. Шаблоны более крупных приложений отличаются более существенно, и именно по этим причинам (которые выходят за рамки данной статьи) я предпочитаю такие инструменты, как Ember. Но как и зачем связывать состояние с DOM - это что-то почти универсальное, от Backbone до Angular 6.

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

Есть два типа людей, которые смотрят на JS-фреймворки свысока и заявляют, что в них нет необходимости.

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

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

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