Фундаментальная причина существования современных фреймворков

внешний интерфейс JavaScript внешний фреймворк

Оригинальная ссылка:medium.com/ведущий выпускник/он и…

предисловие

Я видел, как многие люди слепо используют что-то вродеReact,AngularилиVueТакой современный каркас. Эти фреймворки предлагают много интересного, но часто люди игнорируют первопричину их существования.

Не то, что мы думали по следующим причинам:

  1. Они основаны на компонентах;
  2. У них сильные сообщества;
  3. У них есть много сторонних библиотек для решения проблемы;
  4. У них много сторонних компонентов;
  5. У них есть расширения для браузера, помогающие в отладке;
  6. Они подходят для одностраничных приложений.

Самые основные, фундаментальные и самые глубокие причины таковы:

Синхронизация пользовательского интерфейса с состоянием очень сложна

Зачем

Предположим, вы разрабатываете такое требование:

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

Дизайн взаимодействия с пользовательским интерфейсом выглядит следующим образом:

  1. Поле ввода имеет пустое состояние (с подсказкой)
  2. После ввода адреса электронной почты соответствующий Почтовые ящики, у каждого адреса есть кнопка удаления справа.

Прототип выглядит следующим образом:

Форма представляет собой массив объектов, содержащих адреса электронной почты и уникальные идентификаторы. Изначально он будет пуст. После ввода почтового возврата добавьте элемент в массив и обновите пользовательский интерфейс. Когда пользователь нажимает «Удалить», удаляет соответствующий элемент и обновляет пользовательский интерфейс.

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

Я слышал, как ты сказал это снова, и что? Хорошо, давайте посмотрим, как это реализовать без фреймворка.

Нативная реализация относительно сложного пользовательского интерфейса

// html
<html>
  <body>
    <div id="addressList">
      <form>
        <input>
        <p class="help">Type an email address and hit enter</p>
        <ul>
        </ul>
      </form>
    </div>
  </body>
</html>

// js
class AddressList {
  constructor(root) {
    // state variables
    this.state = []
    // UI variables
    this.root = root
    this.form = root.querySelector('form')
    this.input = this.form.querySelector('input')
    this.help = this.form.querySelector('.help')
    this.ul = root.querySelector('ul')
    this.items = {} // id -> li element
    // event handlers
    this.form.addEventListener('submit', e => {
      e.preventDefault()
      const address = this.input.value
      this.input.value = ''
      this.addAddress(address)
    })
    this.ul.addEventListener('click', e => {
      const id = e.target.getAttribute('data-delete-id')
      if (!id) return // user clicked in something else  
      this.removeAddress(id)
    })
  }
  addAddress(address) {
    // state logic
    const id = String(Date.now())
    this.state = this.state.concat({ address, id })
    // UI logic
    this.updateHelp()
    const li = document.createElement('li')
    const span = document.createElement('span')
    const del = document.createElement('a')
    span.innerText = address
    del.innerText = 'delete'
    del.setAttribute('data-delete-id', id)
    this.ul.appendChild(li)
    li.appendChild(del)
    li.appendChild(span)
    this.items[id] = li
  }
  removeAddress(id) {
    // state logic
    this.state = this.state.filter(item => item.id !== id)
    // UI logic
    this.updateHelp()
    const li = this.items[id]
    this.ul.removeChild(li)
  }
  // utility method
  updateHelp() {
    if (this.state.length > 0) {
      this.help.classList.add('hidden')
    } else {
      this.help.classList.remove('hidden')
    }
  }
}

const root = document.getElementById('addressList')
new AddressList(root);

адрес кода:код спрей.IO/GI ворота e-pass E/devil...

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

В этом примереHTMLОтвечает за создание статических страниц,JavaScriptпройти черезdocument.createElementИзменятьDOMструктура.

Это приводит к первому вопросу:

Код JavaScript, связанный с созданием пользовательского интерфейса, сложен, и создание пользовательского интерфейса разделено на две части. Мы могли бы использовать innerHTML, хотя он более читаем, снижает производительность страницы и может иметь CSRF-уязвимости.

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

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

Мало того, что это трудно писать и трудно об этом рассуждать, но, что более важно, это еще и очень хрупко.

Предположим, нам нужно реализовать функцию синхронизации списка с сервером, нам нужно сравнить данные с данными, возвращаемыми сервером.

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

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

Отзывчивость спасает все

Фреймворки используются не из-за сообщества, не из-за инструментов, не из-за экологии, не из-за сторонних библиотек...

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

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

We define the UI in a single shot, not having to write particular UI code in every action, and we always get the same output due to a particular state: the framework automatically updates it after the state changes.

Как работает фреймворк?

Есть две основные стратегии:

  1. Перерендерите весь компонент, как React. Когда состояние в компоненте изменяется, новая структура DOM вычисляется в памяти и сравнивается с существующей структурой DOM. На самом деле это очень дорого. Поэтому принимается виртуальный DOM, а реальная структура DOM изменяется после расчета изменения путем сравнения разницы между виртуальным DOM до и после изменения состояния. Этот процесс называется примирением.

  2. Отслеживайте изменения с помощью наблюдателей, таких как Angular и Vue. Свойства состояния в приложении отслеживаются, и при их изменении перерисовываются соответствующие DOM-элементы.

как насчет веб-компонентов

Во многих случаях люди сравнивают React, Angular и Vue с веб-компонентами. Эти люди явно не понимают величайшего преимущества этих фреймворков: синхронизации пользовательского интерфейса с состоянием.

Веб-компоненты не предоставляют этот механизм синхронизации. это просто обеспечивает<template>Этикетка. Если вы хотите синхронизировать пользовательский интерфейс и состояние при использовании веб-компонентов в своем приложении, вам необходимо сделать это вручную разработчиком или использовать связанную библиотеку.

Разработать фреймворк самостоятельно?

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

Вот ядро ​​фреймворка, базовый класс для всех компонентов.

Мне нравится узнавать, как все работает — виртуальная реализация DOM. Итак, почему мы изучаем реализацию Virtual DOM?

Это ядро ​​фреймворка, базовый класс для любого компонента.

Вот переписанный компонент AddressList (с использованием Babel для поддержки JSX).

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

В заключение

  1. Основная проблема, которую решают современные фреймворки JavaScript, — синхронизация пользовательского интерфейса с состоянием.
  2. Написание сложных, эффективных и простых в обслуживании интерфейсов пользовательского интерфейса на простом JavaScript практически невозможно.
  3. Веб-компоненты не предоставляют решение для синхронизации пользовательского интерфейса с состоянием.
  4. Разработать собственный фреймворк с использованием существующей виртуальной библиотеки DOM несложно, но не рекомендуется.

наконец

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