Рубрики
Без рубрики

Реактивность Vuejs с нуля

Целью статьи состоит в том, чтобы объяснить, как современная реакционная способность данных в JavaScript может быть реализована с нуля, используя систему Vuejs в качестве примера.

Автор оригинала: Norman Köhring.

Обложка фото из “Реактивность в глубине”, vuejs v1 Документация

Эта статья изначально появилась в моем личном блоге: https://log.koehr.in/2017/08/17/vuejs-reactivity-from-scriatch. Его цель состоит в том, чтобы объяснить, как современная реакционная способность к данным в JavaScript может быть реализована с нуля, используя систему Vuejs в качестве примера.

Vuejs – это звездный новичок в мире JavaScript Framework. Люди любят, как это делает сложные вещи очень простыми, но исполнителями. Одним из более захватывающих особенностей является его, казалось бы, волшебная реактивность. Обычные данные объекты в компонентах волшебно вызывают рерандер при изменении свойства.

Пример минимальной реактивности

Кнопка щелчка вызывает функцию, которая просто назначает новое значение для свойства. Тем не менее шаблон становится автоматически реренрес. Но мы все знаем, что нет прямой вовлеченности, верно? Так как это на самом деле работает?

Магия Getter и Setters

С ES5 Стандарт JavaScript получил много захватывающих новых функций. Некоторые из них сильно недооценивают и недостаточно использованы на мой взгляд. Геттерс и сортировки являются примером. Если вы никогда не слышали о них, я бы порекомендовал вас прочитать Джон Рийсс Шт на них.

Как только вы узнаете, какие GetTers и Getters: функции прозрачно призваны к каждому доступу к собственности, вы уже можете знать, где это идет. Борьси! Все Fairydust внезапно исчезает.

Автоматические getbers и citners

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

Аннотация: Функция, которая получает объект и возвращает один со свойствами, заменяемыми Getter и Devices, которые, по вызову, рерандер шаблоном. Все идет нормально. Если вы действительно нетерпеливы, вы можете найти Последний код в jsfiddle Отказ

Начнем с очень простого подхода:

простой подход

Функция, итерация через все объектные клавиши и создает новый объект с Getter и Benters на их месте. Это также может напрямую манипулировать оригинальным объектом:

Прямая манипуляция объектами

Я лично не люблю манипулировать существующим объектом и предпочитаю первый способ.

Представляем: Object.DefineProperty.

Теперь, прежде чем мы продолжим с уничтожением наших фантазий Fairydust Computing, посмотрим, есть ли удобный способ к тому, что мы сделали сейчас. Здесь я представляю Объект.defineProperty , что позволяет устанавливать все возможные атрибуты для свойств объекта. Вы можете найти Подробное описание на MDN Отказ

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

Более читаемое благодаря объекту.

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

Шаблон для бедных

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

Простые визуализации

Этот код описывает очень простой компонент, который имеет объект данных и функцию рендера. Если это называется, он заменяет innerhtml данного элемента содержимого с отображенным выходом. Аккуратный! Давайте сделаем данные реактивными!

Реактивная компонент

Как начать, должно быть достаточно, чтобы просто сделать свойство данных реагировать:

Недвижимость реактивных данных

Да, это, кажется, хорошо, но это на самом деле не обновляется шаблон. Что становится понятно после взгляда на строку 11-14: нет рендеринга звонка когда-либо. Но реактивный Не следует знать о рендеринге компонентов, верно? Давайте попробуем более общий подход с обратным вызовом:

Render Callback

Да, это работает и так далее, но похоже, что мы медленно спотыкаются от элегантности в нашем коде. Изменения в реактивный () Похоже, в порядке, но эта функция связывает чудовищность в строке 31 – это то, что мы лучше спрятались от наших родителей. Давайте введем компонентную завод, прежде чем мы получим выгнан или в конечном итоге в себе ненависть к себе:

Компоненты из завода

Прохладный! Это работает. CreateComponent () Функция просто делает все грязные работы для нас и возвращает приятный, реактивный компонент, который по-прежнему просто простой объект. Если у вас есть этот код в локальной установке и запустите что-то вроде Компонент.data.name Затем он будет автоматически рерандер на шаблон, чтобы показать «Hello Ada Lovelace».

Вложенные структуры данных

Все прохладные и бедра, но что происходит в следующем сценарии:

Вложенные объекты разбивают все

Установка более глубоких вложенных свойств (линия 44 45) не работает вообще. Причина в том, что реакционная способность работает только на первом уровне гнездования объекта данных. Теперь вы могли бы сказать: легко, мы просто установили весь объект одновременно:

мошенничество

Но это не совсем то, что мы стремимся, не так ли? То, что нам нужно, это способ, который делает все вложенные объекты реагировать в рекурсивный путь. Удивительно, что это просто нужно купе линий:

Реагирует все вещи

Только три строки (7-9), где добавлено. Они называют реактивный () По данной ценности в случае это объект. Теперь уровень гнездования больше не имеет значения. Реагируйте все вещи !!

Несколько компонентов

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

несколько компонентов

Оно делает! Ура!

Внимательный читатель мог видеть изменение, которое пронизировало в строку 7: потому что тип массива является объектом, здесь необходимо сделать дополнительную проверку. В противном случае массив будет преобразован в простой объект с помощью клавиш 0, 1 и т. Д.

Но что произойдет сейчас, когда мы напрямую манипулируют массив?

Массивы ненавидят тебя

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

Реактивные массивы

Как описано в Раздел предостережения Руководства Vuejs по поводу рендеринга списков есть несколько … хорошо предостережения с реактивностью массива. Пишет:

Due to limitations in JavaScript, Vue cannot detect the following changes to an array:
1. When you directly set an item with the index, e.g. vm.items[indexOfItem] = newValue
2. When you modify the length of the array, e.g. vm.items.length = newLength

Хорошо, достаточно честно. Так что происходит в Vue, чтобы сделать массивы реактивными? Волшебной пыли? К сожалению, да. И этот материал дороги! Нах, просто шучу. Конечно, это снова не вовлечено никакой магии. Извините, моя дорогая ролевые друзья. Что на самом деле происходит, так это то, что массивы получают свои манипулирующие функции, замененные на обернутую версию, которая уведомляет компонент об изменениях. Источник к этой функциональности находится в Core/Observer/Array.js Отказ

Подход Vuejs довольно сложный, но может быть конденсирован к чему-то вроде то, что видно в первых 24 линиях здесь:

Улучшение функций массива

Так что это довольно большой кусок для переваривания. Новая функция Реактивируйте Запускается с создания копии исходного массива (запомнить? Я не люблю управлять исходным объектом). Затем для каждой функции в списке функций манипуляционного массива оригинал сохраняется, который затем заменяется функцией обертки. Эта функция обертки просто вызывает обратный вызов Render дополнительно к исходной функции массива.

Теперь и lipsumcomponent.data.content больше не устанавливается, но использует перезаписанный метод push. Установка его напрямую не будет работать. Исправление, которое приводит нас к последнему шагу:

Реактивность на набор

На данный момент функция сеттера не заботилась о стоимости. Если бы это был бы вложенный объект, его дети не будут реактивными. Это означает, если вы установите data.x к объекту {foo: 1} а затем изменить foo data.x.foo ++ Шаблон не будет рерандер. Это должно быть изменено:

Обратите внимание, сеттер

Вместо того, чтобы установить простое значение, Реактивное (значение, обратный вызов) называется в очереди 49. Это небольшое изменение работает только до определенного момента самостоятельно. Функция должна решить, что делать с нееместными или массивами, которые происходят сейчас в качестве первого шага в реактивный () Отказ Обычный не объект (запоминание: массивы – это объекты) просто возвращаются, как это (линия 30), массивы будут возвращены в их реактивной версии (строка 31).

Заключение

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

В о 70 SLOC Мы построили полностью реактивную компонентную систему. Мы использовали использование Getter, Benters и Объект.defineProperty И узнал, что я не люблю манипулировать объектами напрямую. За исключением последнего пункта, это должна быть ценная информация, которая может стать удобной в будущем.

Что еще можно сделать, вы можете спросить? Код Vuejs более сложный и обрабатывает некоторые случаи EGDE, которые я не упоминал ради простоты. Например, если еще впереди реагируемый объект уже имеет несколько геттерс и/или загадателей, они будут перезаписаны нашим простым решением. Vuejs ‘ непременно использует Object.GetownPropertyDescription Чтобы получить подробную информацию о недвижимости, она собирается обернуть и включает в себя существующие Getter и Getters, если применимо. Он также игнорирует не настраиваемым (не предназначен для изменения вообще) свойства. Как это работает можно найти В исходном коде Отказ