Перейти к содержимому

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

Alpine является «реактивным» в том смысле, что когда вы меняете часть данных, всё, что зависит от этих данных, «реагирует» автоматически на это изменение.

Каждая часть реактивности, происходящая в Alpine, происходит из-за двух очень важных реактивных функций в ядре Alpine: Alpine.reactive() и Alpine.effect().

Понимание этих двух функций даст вам суперспособности как разработчика Alpine, а также как веб-разработчика в целом.

Давайте сначала посмотрим на Alpine.reactive(). Эта функция принимает объект JavaScript в качестве параметра и возвращает «реактивную» версию этого объекта. Например:

let data = { count: 1 };
let reactiveData = Alpine.reactive(data);

Под капотом, когда Alpine.reactive получает data, он помещает их в собственный прокси-сервер JavaScript.

Прокси — это особый вид объекта в JavaScript, который может перехватывать вызовы «get» и «set» к объекту JavaScript.

Переменная reactiveData должна вести себя точно так же, как data. Например:

console.log(data.count); // 1
console.log(reactiveData.count); // 1
reactiveData.count = 2;
console.log(data.count); // 2
console.log(reactiveData.count); // 2

Здесь вы видите, что, поскольку reactiveData представляет собой тонкую оболочку data, любые попытки получить или установить свойство будут вести себя точно так же, как если бы вы напрямую взаимодействовали с data.

Основное отличие здесь заключается в том, что каждый раз, когда вы изменяете или извлекаете (получаете или устанавливаете) значение из reactiveData, Alpine узнает об этом и может выполнить любую другую логику, которая зависит от этих данных.

Alpine.reactive — это только первая половина истории. Alpine.effect — это вторая половина, давайте углубимся.

Alpine.effect принимает в качестве параметра функцию обратного вызова. Как только вызывается Alpine.effect, она выполняет переданную функцию и отслеживает чтение реактивных данных. Каждое реактивное свойство, прочитанное во время этого выполнения, становится зависимостью. Когда одно из этих свойств впоследствии изменяется, Alpine снова выполняет функцию обратного вызова. Например:

let data = Alpine.reactive({ count: 1 });
Alpine.effect(() => {
console.log(data.count);
});

При первом запуске этого кода в консоли отобразится «1». При каждом изменении свойства data.count его новое значение будет выводиться в консоль.

Это механизм, который раскрывает всю реактивность ядра Alpine.

Зависимости собираются во время выполнения эффекта. Чтение data.count внутри функции обратного вызова регистрирует это свойство в эффекте. Последующее изменение data.count уведомляет эффект, после чего он выполняется снова и собирает зависимости, использованные во время этого выполнения.

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

Alpine делегирует это поведение пакету реактивности Vue. Для более подробного объяснения модели с прокси, картой зависимостей и track/trigger см. внутреннее устройство реактивности Vue.

Чтобы связать всё воедино, давайте посмотрим на простой пример компонента «счётчик» вообще без использования синтаксиса Alpine, а только с использованием Alpine.reactive и Alpine.effect:

<button class="increment">
Увеличить <span class="result"></span>
</button>
<script>
document.addEventListener('alpine:init', () => {
let button = document.querySelector('button.increment');
let span = document.querySelector('span.result');
let data = Alpine.reactive({ count: 1 });
Alpine.effect(() => {
span.textContent = data.count;
});
button.addEventListener('click', () => {
data.count = data.count + 1;
});
});
</script>

Как видите, вы можете сделать любые данные реактивными, а также можете обернуть любую функциональность в Alpine.effect.

Эта комбинация открывает невероятно мощную парадигму программирования для веб-разработки. Не ограничивайте себя ни в чём.