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 при внесении изменений в stateobject. Следующее изменение отражено в пользовательском интерфейсе.

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.

Щелкните здесь, чтобы получить образец книги.