API композиции Vue.js предоставляет новый способ управления реактивностью. Он состоит из набора функций Reactive API, а также средства для регистрации хуков жизненного цикла с использованием импортированных функций.
В книге Vue.js Composition API мы рассмотрим, как реализовать этот реактивный API с нуля. Затем мы реализуем функциональность мастер-детали.
Глава 01: Создание реактивного API
Мы начинаем наше учебное путешествие с понимания того, что такое реактивность, как реализована в Vue 3. Представьте, что у нас есть простой объект state
и функция render
.
const state = { message : 'This is a message' };
function render(state){ document .getElementById('UI') .innerHTML = `<span>${state.message}</span>`; }
При вызове функции render(state)
сообщение отображается в пользовательском интерфейсе.
render(state);
Теперь предположим, что мы изменили свойство message
объекта state
.
state.message = 'A new message';
Изменение объекта state
не отражается в пользовательском интерфейсе. Если мы хотим, чтобы это произошло, нам нужно снова вызвать функцию render
.
state.message = 'A new message';
render(state);
Прокси
Нам нужен способ обнаружить изменения объекта и вызвать функцию render
. В этом может помочь объект Прокси.
Прокси-объект определяет настраиваемое поведение для таких операций, как получение или установка свойства. В следующем примере показан прокси, вызывающий функцию render
при изменении свойств.
const reactiveHandler = { set: function(obj, prop, value) { obj[prop] = value; render(obj); return true; } };
const state = new Proxy({ message: 'This is a message' }, reactiveHandler);
reactiveHandler
предоставляет обработчик для установки свойства объекта. Обработчик изменяет свойство, вызывает render
с измененным объектом и возвращает true
, указывая на успешную операцию.
реактивный ()
Реактивность в Vue относится к процессу автоматического обновления пользовательского интерфейса при изменении объекта состояния.
Мы можем сделать объект реактивным, просто используя новую служебную функцию, обертывающую вызов прокси.
function reactive(obj){ return new Proxy(obj, reactiveHandler); }
const state = reactive({ message: 'This is a message' });
Функция reactive
принимает объект и возвращает новый прокси-объект, обертывающий его. Все взаимодействия с объектом, такие как настройка и получение данных, проходят через обработчик прокси.
На этом этапе нет необходимости вручную вызывать функцию render
при внесении изменений в state
object. Следующее изменение отражено в пользовательском интерфейсе.
state.message = 'A new message';
watchEffect ()
У этого решения есть недостаток. В нем явно указывается, какая функция должна быть вызвана. Мы хотим иметь возможность обнаруживать эту функцию подписчика, не вызывая ее явно в определении прокси.
JavaScript - это однопоточный язык. Это означает, что в определенный момент может выполняться одна функция. Мы можем создать служебную функцию, которая выполняет эту функцию, но также сохраняет ее в переменной.
Рассмотрим следующую watchEffect
служебную функцию.
let currentFunc = null;
function watchEffect(f){
currentFunc = f;
f();
currentFunc = null;
}
watchEffect
выполняет функцию f
. Он сохраняет функцию в переменной currentFunc
, предоставляя нам доступ к выполняющейся в данный момент функции. Затем он выполняет функцию f
и сбрасывает переменную currentFunc
на null
.
Вместо прямого выполнения render(state)
мы можем вызвать его с помощью утилиты watchEffect
.
watchEffect(() => {
render(state);
});
На этом этапе у нас есть доступ к выполняющейся в данный момент функции в обработчике reactiveHandler
.
Обработчик get
возвращает запрошенное свойство и сохраняет текущую выполняемую функцию в качестве подписчика.
Обработчик set
изменяет свойство и вызывает функцию подписчика, зарегистрированную в обработчике get
.
let subscriber = null;
const reactiveHandler = {
get: function (obj, prop) {
if(currentFunc != null){
subscriber = currentFunc;
}
return obj[prop];
},
set: function(obj, prop, value) {
obj[prop] = value;
subscriber(obj);
return true;
}
};
В этом примере нам не нужно указывать функцию, которая будет вызываться при изменении состояния. Функция обнаруживается автоматически, если ее вызов помещается в служебную программу watchEffect
.