Реактивность - это автоматическая синхронизация между состоянием и DOM.Это то, что библиотеки представлений, такие как Vue и React, пытаются делать в своей основе.Они делают это по-своему.
Я вижу систему реактивности Вью как двойную.Одна сторона медали - механизм обновления DOM.Давайте сначала разберемся с этим.
Допустим, у вас есть компонент с шаблоном, например:
<template>
<div>{{ foo }}</div>
</template>
<script>
export default {
data() {
return {foo: 'bar'};
}
}
</script>
Этот шаблон преобразуется в функцию рендеринга.Это происходит во время сборки с использованием vue-loader .Функция рендеринга для приведенного выше шаблона выглядит примерно так:
function anonymous(
) {
with(this){return _c('div',[_v(_s(foo))])}
}
Функция рендеринга запускается в браузере и при ее выполнении возвращает Vnode (виртуальный узел).Виртуальный узел - это просто простой объект JavaScript, который представляет собой реальный узел DOM, план узла DOM.Приведенная выше функция рендеринга при выполнении возвращает что-то вроде:
{
tag: 'div',
children: ['bar']
}
Затем Vue создает фактический узел DOM из этого шаблона Vnode и помещает его в DOM.
Позже, скажем, foo
значение изменяется, и как-то функция рендеринга запускается снова.Это даст другой Vnode.Затем Vue объединяет новый Vnode со старым и вносит в DOM только необходимые изменения, необходимые для DOM.
Это дает нам механизм для эффективного обновления DOM, принимающего самое последнее состояние для компонента.Если каждый раз, когда вызывается функция рендеринга компонента, когда изменяется любое его состояние (данные, реквизиты и т. Д.), Мы получаем полную систему реактивности.
Вот где появляется другая сторона монеты реактивности Vue. Иэто реактивные геттеры и сеттеры.
Это будет хорошее время для понимания API Object.defineProperty , если вы еще не знаете об этом.Потому что система реактивности Vue опирается на этот API.
TLDR;это позволяет нам переопределять доступ и присваивание свойств объекта с помощью наших собственных функций получения и установки.
Когда Vue создает экземпляр вашего компонента, он просматривает все свойства ваших данных и реквизит и переопределяет их, используя Object.defineProperty
.
То, что он на самом деле делает, это определяет методы получения и установки для каждого свойства данных и свойств.Таким образом, он переопределяет точечный доступ (this.data.foo) и присваивание (this.data.foo = someNewValue) этого свойства.Поэтому всякий раз, когда эти два действия происходят с этим свойством, наши переопределения вызываются.Таким образом, у нас есть крюк, чтобы что-то с ними сделать.Мы вернемся к этому немного позже.
Также для каждого свойства создается новый экземпляр класса Dep () .Он называется Dep
, потому что каждое свойство data или props может иметь отношение dep к функции рендеринга компонента.
Но сначала важно знать, что функция рендеринга каждого компонента вызывается в наблюдателе .Таким образом, наблюдатель имеет связанную с ним функцию рендеринга компонента.Watcher используется и для других целей, но когда он наблюдает за функцией рендеринга компонента, это рендер watcher .Наблюдатель назначает себя как текущий запущенный наблюдатель , где-то доступный глобально (в статическом свойстве Dep.target ), а затем запускает функцию рендеринга компонента .
Теперь вернемся к реактивным геттерам и сеттерам.Когда вы запускаете функцию рендеринга, к свойствам состояния обращаются.Например, this.data.foo
.Это вызывает наше переопределение геттера.Когда вызывается геттер, вызывается dep.depend()
.Это проверяет, есть ли текущий запущенный наблюдатель, назначенный в Dep.target
, и если это так, он назначает этого наблюдателя в качестве подписчика этого объекта dep.Он называется dep.depend()
, потому что мы делаем зависимость watcher
от dep
.
_______________ _______________
| | | |
| | subscribes to | |
| Watcher | --------------> | Dep |
| | | |
|_____________| |_____________|
, что совпадает с
_______________ _______________
| | | |
| Component | subscribes to | it's |
| render | --------------> | state |
| function | | property |
|_____________| |_____________|
Позже, когда свойство состояния обновляется, вызывается установщик, и связанный объект dep уведомляет своих подписчиков о новом значении.Подписчики - это наблюдатели, которые осведомлены о функции рендеринга, и именно так функция рендеринга компонентов вызывается автоматически при изменении ее состояния.
Это завершает систему реактивности.У нас есть способ вызывать функцию рендеринга компонента всякий раз, когда изменяется его состояние.И у нас есть способ эффективно обновить DOM, как только это произойдет.
Таким образом, Vue создал связь между свойством состояния и функцией рендеринга.Vue точно знает, какую функцию рендеринга выполнять при изменении свойства состояния.Это очень хорошо масштабируется и в основном убирает категорию ответственности за оптимизацию производительности из рук разработчика.Разработчикам не нужно беспокоиться о визуализации компонентов, независимо от того, насколько велико дерево компонентов.Чтобы предотвратить это, React, например, предоставляет PureComponent или shouldComponentUpdate.В Vue это просто не нужно, поскольку Vue точно знает, какой компонент следует перерисовать при изменении любого состояния.
Но теперь, когда мы знаем, как Vue заставляет вещи реагировать, мы можем придумать способ немного оптимизировать вещи.Представьте, что у вас есть компонент блога.Вы получаете некоторые данные из бэкэнда и отображаете их в браузере с помощью компонента Vue.Но нет необходимости, чтобы данные блога были реактивными, потому что они, скорее всего, не изменятся.В такой ситуации мы можем сказать Vue пропустить активацию таких данных путем замораживания объектов.
export default {
data: () => ({
list: {}
}),
async created() {
const list = await this.someHttpClient.get('/some-list');
this.list = Object.freeze(list);
}
};
Oject.freeze среди прочего отключает возможность конфигурирования объекта.Вы не можете переопределить свойства этого объекта снова, используя Object.defineProperty
.Поэтому Vue пропускает всю настройку реактивности для таких объектов.
Кроме того, изучая исходный код Vue самостоятельно, по этой теме доступно два чрезвычайно полезных ресурса:
- Расширенный компонент Vue Mastery курс
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ”* * *” * * * * * * * * ЕВАН *, * * * * * * * ЕВАН *, 11: * * * * * * * * * * * * * *).Джейсон Ю.
Создание простого виртуального DOM с нуля