Реактивность по запросу в Vue 3
Опубликовано: 2022-03-11Помимо замечательных улучшений производительности, недавно выпущенный Vue 3 также принес несколько новых функций. Пожалуй, наиболее важным введением является Composition API . В первой части этой статьи мы повторяем стандартную мотивацию для нового API: лучшая организация кода и повторное использование. Во второй части мы сосредоточимся на менее обсуждаемых аспектах использования нового API, таких как реализация функций, основанных на реактивности, которые были невыразимы в системе реактивности Vue 2.
Мы будем называть это реактивностью по требованию . После введения соответствующих новых функций мы создадим простое приложение для работы с электронными таблицами, чтобы продемонстрировать новую выразительность системы реактивности Vue. В самом конце мы обсудим, какое практическое применение может иметь это улучшение реактивности по требованию.
Что нового в Vue 3 и почему это важно
Vue 3 — это серьезная переработка Vue 2, в которой представлено множество улучшений, но почти полностью сохранена обратная совместимость со старым API.
Одной из самых значительных новых функций Vue 3 является Composition API . Его введение вызвало много споров, когда оно впервые обсуждалось публично. Если вы еще не знакомы с новым API, мы сначала опишем его мотивацию.
Обычной единицей организации кода является объект JavaScript, ключи которого представляют различные возможные типы частей компонента. Таким образом, объект может иметь один раздел для реактивных данных ( data
), другой раздел для вычисляемых свойств ( computed
), еще один для методов компонента ( methods
) и т. д.
В соответствии с этой парадигмой компонент может иметь несколько несвязанных или слабо связанных функций, внутренняя работа которых распределена между вышеупомянутыми разделами компонента. Например, у нас может быть компонент для загрузки файлов, который реализует две принципиально разные функции: управление файлами и систему, управляющую анимацией состояния загрузки.
Часть <script>
может содержать что-то вроде следующего:
export default { data () { return { animation_state: 'playing', animation_duration: 10, upload_filenames: [], upload_params: { target_directory: 'media', visibility: 'private', } } }, computed: { long_animation () { return this.animation_duration > 5; }, upload_requested () { return this.upload_filenames.length > 0; }, }, ... }
У этого традиционного подхода к организации кода есть свои преимущества, в основном в том, что разработчику не нужно беспокоиться о том, где написать новый фрагмент кода. Если мы добавляем реактивную переменную, мы вставляем ее в раздел data
. Если мы ищем существующую переменную, мы знаем, что она должна быть в разделе data
.
Этот традиционный подход разделения реализации функциональности на разделы ( data
, computed
и т. д.) подходит не во всех ситуациях.
Часто приводятся следующие исключения:
- Работа с компонентом с большим количеством функций. Если мы хотим обновить наш код анимации с возможностью, например, отложить начало анимации, нам придется прокручивать/перепрыгивать между всеми соответствующими разделами компонента в редакторе кода. В случае с нашим компонентом для загрузки файлов сам компонент невелик, и количество реализуемых им функций также невелико. Таким образом, в этом случае переход между разделами не является проблемой. Эта проблема фрагментации кода становится актуальной, когда мы имеем дело с большими компонентами.
- Еще одна ситуация, когда традиционный подход не работает, — это повторное использование кода. Часто нам нужно сделать определенную комбинацию реактивных данных, вычисляемых свойств, методов и т. д. доступной более чем в одном компоненте.
Vue 2 (и обратно совместимый Vue 3) предлагают решение большинства проблем организации кода и повторного использования: примеси .
Плюсы и минусы миксинов в Vue 3
Миксины позволяют извлекать функциональные возможности компонента в отдельную единицу кода. Каждая функциональность помещается в отдельный миксин, и каждый компонент может использовать один или несколько миксинов. Части, определенные в миксине, могут использоваться в компоненте, как если бы они были определены в самом компоненте. Примеси немного похожи на классы в объектно-ориентированных языках, поскольку они собирают код, связанный с заданной функциональностью. Как и классы, примеси могут наследоваться (использоваться) в других единицах кода.
Однако рассуждать с примесями сложнее, поскольку, в отличие от классов, примеси не обязательно проектировать с учетом инкапсуляции. Миксины могут быть наборами свободно связанных фрагментов кода без четко определенного интерфейса с внешним миром. Использование более одного миксина одновременно в одном и том же компоненте может привести к тому, что компонент будет труден для понимания и использования.
Большинство объектно-ориентированных языков (например, C# и Java) не одобряют или даже запрещают множественное наследование, несмотря на тот факт, что парадигма объектно-ориентированного программирования имеет инструменты для решения такой сложности. (Некоторые языки допускают множественное наследование, например C++, но композиция по-прежнему предпочтительнее наследования.)
Более практичная проблема, которая может возникнуть при использовании примесей в Vue, — это конфликт имен, возникающий при использовании двух или более примесей, объявляющих общие имена. Здесь следует отметить, что если стратегия Vue по умолчанию для обработки конфликтов имен не идеальна в данной ситуации, разработчик может скорректировать стратегию. Это происходит за счет увеличения сложности.
Другая проблема заключается в том, что примеси не предлагают что-то вроде конструктора класса. Это проблема, потому что часто нам нужно, чтобы функциональность, которая очень похожа, но не совсем одинаковая, присутствовала в разных компонентах. В некоторых простых случаях это можно обойти с помощью фабрик примесей.
Поэтому примеси — не идеальное решение для организации и повторного использования кода, и чем больше проект, тем серьезнее становятся их проблемы. Vue 3 представляет новый способ решения тех же проблем, касающихся организации и повторного использования кода.
Composition API: ответ Vue 3 на организацию и повторное использование кода
Composition API позволяет нам (но не требует от нас) полностью отделить части компонента. Каждая часть кода — переменная, вычисляемое свойство, часы и т. д. — может быть определена независимо.
Например, вместо объекта, который содержит раздел data
, содержащий ключ animation_state
со значением (по умолчанию) «playing», теперь мы можем написать (в любом месте нашего кода JavaScript):
const animation_state = ref('playing');
Эффект почти такой же, как от объявления этой переменной в секции data
какого-нибудь компонента. Единственное существенное отличие состоит в том, что нам нужно сделать ref
, определенную вне компонента, доступной в компоненте, где мы собираемся ее использовать. Мы делаем это, импортируя его модуль в место, где определен компонент, и возвращая ref
из раздела setup
компонента. Мы пока пропустим эту процедуру и просто сосредоточимся на новом API. Реактивность в Vue 3 не требует компонента; на самом деле это автономная система.
Мы можем использовать переменную animation_state
в любой области видимости, в которую мы импортируем эту переменную. После создания ref
мы получаем и устанавливаем его фактическое значение с помощью ref.value
, например:
animation_state.value = 'paused'; console.log(animation_state.value);
Нам нужен суффикс '.value', поскольку в противном случае оператор присваивания присвоил бы (нереактивное) значение «paused» переменной animation_state
. Реактивность в JavaScript (как когда она реализована через defineProperty
, как в Vue 2, так и когда она основана на Proxy
, как в Vue 3) требует объекта, с ключами которого мы можем работать реактивно.
Обратите внимание, что это имело место и в Vue 2; там у нас был компонент в качестве префикса для любого реактивного члена данных ( component.data_member
). Если и до тех пор, пока стандарт языка JavaScript не введет возможность перегружать оператор присваивания, реактивные выражения потребуют, чтобы объект и ключ (например, animation_state
и value
, как указано выше) появлялись в левой части любой операции присваивания, где мы хотим сохранить реактивность.
В шаблонах мы можем опустить .value
, так как Vue должен предварительно обработать код шаблона и может автоматически определять ссылки:
<animation :state='animation_state' />
Теоретически компилятор Vue может аналогичным образом предварительно обрабатывать часть <script>
компонента Single File Component (SFC), вставляя .value
там, где это необходимо. Однако использование refs
будет зависеть от того, используем ли мы SFC или нет, поэтому, возможно, такая функция даже нежелательна.
Иногда у нас есть объект (например, объект Javascript или массив), который мы никогда не собираемся заменять совершенно другим экземпляром. Вместо этого нас может интересовать только изменение полей с ключами. В этом случае есть сокращение: использование reactive
вместо ref
позволяет нам обойтись без .value
:
const upload_params = reactive({ target_directory: 'media', visibility: 'private', }); upload_params.visibility = 'public'; // no `.value` needed here // if we did not make `upload_params` constant, the following code would compile but we would lose reactivity after the assignment; it is thus a good idea to make reactive variables ```const``` explicitly: upload_params = { target_directory: 'static', visibility: 'public', };
Разделенная реактивность с ref
и reactive
не является совершенно новой функцией Vue 3. Она была частично представлена в Vue 2.6, где такие несвязанные экземпляры реактивных данных назывались «наблюдаемыми». По большей части можно заменить Vue.observable
на reactive
. Одно из отличий заключается в том, что доступ и изменение объекта, переданного непосредственно в Vue.observable
, являются реактивными, в то время как новый API возвращает прокси-объект, поэтому изменение исходного объекта не будет иметь реактивных эффектов.

Совершенно новым в Vue 3 является то, что другие реактивные части компонента теперь могут быть определены независимо, в дополнение к реактивным данным. Вычисляемые свойства реализованы ожидаемым образом:
const x = ref(5); const x_squared = computed(() => x.value * x.value); console.log(x_squared.value); // outputs 25
Точно так же можно реализовать различные типы часов, методы жизненного цикла и внедрение зависимостей. Ради краткости мы не будем их здесь рассматривать.
Предположим, мы используем стандартный подход SFC к разработке Vue. Мы могли бы даже использовать традиционный API с отдельными разделами для данных, вычисляемых свойств и т. д. Как нам интегрировать небольшие элементы реактивности API композиции с SFC? Vue 3 представляет еще один раздел специально для этого: setup
. Новый раздел можно рассматривать как новый метод жизненного цикла (который выполняется перед любым другим хуком, в частности, перед created
).
Вот пример полного компонента, который интегрирует традиционный подход с Composition API:
<template> <input v-model="x" /> <div>Squared: {{ x_squared }}, negative: {{ x_negative }}</div> </template> <script> import { ref, computed } from 'vue'; export default { name: "Demo", computed: { x_negative() { return -this.x; } }, setup() { const x = ref(0); const x_squared = computed(() => x.value * x.value); return {x, x_squared}; } } </script>
Что нужно вынести из этого примера:
- Весь код Composition API теперь находится в
setup
. Вы можете захотеть создать отдельный файл для каждой функции, импортировать этот файл в SFC и вернуть желаемые биты реактивности изsetup
(чтобы сделать их доступными для остальной части компонента). - Вы можете смешивать новый и традиционный подход в одном файле. Обратите внимание, что
x
, даже если это ссылка, не требует.value
при упоминании в коде шаблона или в традиционных разделах компонента, таких какcomputed
. - И последнее, но не менее важное: обратите внимание, что в нашем шаблоне есть два корневых узла DOM; возможность иметь несколько корневых узлов — еще одна новая функция Vue 3.
Реактивность стала более выразительной в Vue 3
В первой части этой статьи мы коснулись стандартной мотивации Composition API, а именно улучшенной организации кода и повторного использования. Действительно, главное преимущество нового API заключается не в его мощности, а в организационном удобстве, которое он обеспечивает: возможность более четко структурировать код. Может показаться, что это все, что Composition API позволяет реализовать компоненты, которые избегают ограничений уже существующих решений, таких как примеси.
Однако в новом API есть еще кое-что. Composition API на самом деле позволяет не только лучше организовать, но и более мощные реактивные системы. Ключевым компонентом является возможность динамически добавлять реактивность в приложение. Раньше перед загрузкой компонента нужно было определить все данные, все вычисляемые свойства и т. д. Почему добавление реактивных объектов на более позднем этапе может быть полезным? В том, что осталось, мы рассмотрим более сложный пример: электронные таблицы.
Создание электронной таблицы в Vue 2
Инструменты для работы с электронными таблицами, такие как Microsoft Excel, LibreOffice Calc и Google Sheets, имеют своего рода систему реактивности. Эти инструменты представляют пользователю таблицу со столбцами, проиндексированными A–Z, AA–ZZ, AAA–ZZZ и т. д., и строками, пронумерованными числовым образом.
Каждая ячейка может содержать простое значение или формулу. Ячейка с формулой — это, по сути, вычисляемое свойство, которое может зависеть от значений или других вычисляемых свойств. В стандартных электронных таблицах (и в отличие от системы реактивности в Vue) эти вычисляемые свойства даже могут зависеть от самих себя! Такая самореференция полезна в некоторых сценариях, когда желаемое значение получается путем итеративной аппроксимации.

Как только содержимое ячейки изменится, все ячейки, которые зависят от рассматриваемой ячейки, вызовут обновление. Если произойдут дальнейшие изменения, могут быть запланированы дальнейшие обновления.
Если бы нам нужно было создать приложение для работы с электронными таблицами с помощью Vue, было бы естественно спросить, можем ли мы использовать собственную систему реактивности Vue и сделать Vue движком приложения для работы с электронными таблицами. Для каждой ячейки мы могли запомнить ее необработанное редактируемое значение, а также соответствующее вычисленное значение. Вычисляемые значения будут отражать необработанное значение, если это простое значение, а в противном случае вычисляемые значения являются результатом выражения (формулы), которое записывается вместо простого значения.
В Vue 2 способ реализации электронной таблицы состоит в том, чтобы использовать raw_values
как двумерный массив строк, а calculated_values как ( computed_values
) двумерный массив значений ячеек.
Если количество ячеек невелико и фиксировано до загрузки соответствующего компонента Vue, у нас может быть одно необработанное и одно вычисленное значение для каждой ячейки таблицы в нашем определении компонента. Помимо эстетической чудовищности, которую могла бы вызвать такая реализация, таблица с фиксированным количеством ячеек во время компиляции, вероятно, не считается электронной таблицей.
Есть проблемы и с двумерным массивом computed_values
. Вычисляемое свойство всегда является функцией, оценка которой в этом случае зависит от самой себя (вычисление значения ячейки, как правило, требует, чтобы некоторые другие значения уже были вычислены). Даже если бы Vue разрешил самореферентные вычисляемые свойства, обновление одной ячейки привело бы к повторному вычислению всех ячеек (независимо от того, есть зависимости или нет). Это было бы крайне неэффективно. Таким образом, мы могли бы в конечном итоге использовать реактивность для обнаружения изменений в необработанных данных с помощью Vue 2, но все остальное с точки зрения реактивности пришлось бы реализовывать с нуля.
Моделирование вычисляемых значений в Vue 3
С Vue 3 мы можем ввести новое вычисляемое свойство для каждой ячейки. Если таблица растет, вводятся новые вычисляемые свойства.
Предположим, у нас есть ячейки A1
и A2
, и мы хотим, чтобы A2
отображал квадрат A1
, значение которого равно числу 5. Набросок этой ситуации:
let A1 = computed(() => 5); let A2 = computed(() => A1.value * A1.value); console.log(A2.value); // outputs 25
Предположим, мы ненадолго остановимся на этом простом сценарии. Здесь есть проблема; что, если мы захотим изменить A1
так, чтобы он содержал число 6? Предположим, мы пишем это:
A1 = computed(() => 6); console.log(A2.value); // outputs 25 if we already ran the code above
Это не просто изменило значение 5 на 6 в A1
. Переменная A1
теперь имеет совершенно другую идентичность: вычисляемое свойство, которое разрешается в число 6. Однако переменная A2
по-прежнему реагирует на изменения старой идентичности переменной A1
. Таким образом, A2
должен ссылаться не на A1
напрямую, а на какой-то специальный объект, который всегда будет доступен в контексте и расскажет нам, что такое A1
в данный момент. Другими словами, нам нужен уровень косвенности перед доступом к A1
, что-то вроде указателя. В Javascript нет указателей как первоклассных сущностей, но их легко смоделировать. Если мы хотим, чтобы pointer
указывал на value
, мы можем создать объект pointer = {points_to: value}
. Перенаправление указателя сводится к присвоению pointer.points_to
, а разыменование (доступ к указываемому значению) сводится к получению значения pointer.points_to
. В нашем случае поступаем следующим образом:
let A1 = reactive({points_to: computed(() => 5)}); let A2 = reactive({points_to: computed(() => A1.points_to * A1.points_to)}); console.log(A2.points_to); // outputs 25
Теперь мы можем заменить 5 на 6.
A1.points_to = computed(() => 6); console.log(A2.points_to); // outputs 36
На сервере Vue Discord пользователь redblobgames предложил еще один интересный подход: вместо использования вычисляемых значений используйте ссылки, оборачивающие обычные функции. Таким образом, можно аналогичным образом поменять местами функцию без изменения идентификатора самой ссылки.
Наша реализация электронной таблицы будет иметь ячейки, на которые ссылаются ключи некоторого двумерного массива. Этот массив может обеспечить требуемый уровень косвенности. Таким образом, в нашем случае нам не потребуется никакого дополнительного моделирования указателя. Мы могли бы даже иметь один массив, который не различает необработанные и вычисленные значения. Все может быть вычисляемым значением:
const cells = reactive([ computed(() => 5), computed(() => cells[0].value * cells[0].value) ]); cells[0] = computed(() => 6); console.log(cells[1].value); // outputs 36
Однако мы действительно хотим различать необработанные и вычисленные значения, поскольку мы хотим иметь возможность привязать необработанное значение к элементу ввода HTML. Кроме того, если у нас есть отдельный массив для необработанных значений, нам никогда не придется изменять определения вычисляемых свойств; они будут обновляться автоматически на основе необработанных данных.
Реализация электронной таблицы
Давайте начнем с некоторых основных определений, которые по большей части говорят сами за себя.
const rows = ref(30), cols = ref(26); /* if a string codes a number, return the number, else return a string */ const as_number = raw_cell => /^[0-9]+(\.[0-9]+)?$/.test(raw_cell) ? Number.parseFloat(raw_cell) : raw_cell; const make_table = (val = '', _rows = rows.value, _cols = cols.value) => Array(_rows).fill(null).map(() => Array(_cols).fill(val)); const raw_values = reactive(make_table('', rows.value, cols.value)); const computed_values = reactive(make_table(undefined, rows.value, cols.value)); /* a useful metric for debugging: how many times did cell (re)computations occur? */ const calculations = ref(0);
План состоит в том, чтобы каждое computed_values[row][column]
вычислялось следующим образом. Если raw_values[row][column]
не начинается с =
, вернуть raw_values[row][column]
. В противном случае проанализируйте формулу, скомпилируйте ее в JavaScript, оцените скомпилированный код и верните значение. Короче говоря, мы немного схитрим с формулами синтаксического анализа и не будем делать здесь некоторые очевидные оптимизации, такие как кеш компиляции.
Мы предполагаем, что пользователи могут вводить любое допустимое выражение JavaScript в качестве формулы. Мы можем заменить ссылки на имена ячеек, которые появляются в выражениях пользователя, таких как A1, B5 и т. д., ссылкой на фактическое значение ячейки (вычисленное). Следующая функция выполняет эту работу, предполагая, что строки, напоминающие имена ячеек, действительно всегда идентифицируют ячейки (и не являются частью какого-то несвязанного выражения JavaScript). Для простоты будем считать, что индексы столбцов состоят из одной буквы.
const letters = Array(26).fill(0) .map((_, i) => String.fromCharCode("A".charCodeAt(0) + i)); const transpile = str => { let cell_replacer = (match, prepend, col, row) => { col = letters.indexOf(col); row = Number.parseInt(row) - 1; return prepend + ` computed_values[${row}][${col}].value `; }; return str.replace(/(^|[^AZ])([AZ])([0-9]+)/g, cell_replacer); };
Используя функцию transpile
, мы можем получить чистые выражения JavaScript из выражений, написанных в нашем маленьком «расширении» JavaScript со ссылками на ячейки.
Следующим шагом является создание вычисляемых свойств для каждой ячейки. Эта процедура будет происходить один раз в жизни каждой ячейки. Мы можем создать фабрику, которая будет возвращать желаемые вычисляемые свойства:
const computed_cell_generator = (i, j) => { const computed_cell = computed(() => { // we don't want Vue to think that the value of a computed_cell depends on the value of `calculations` nextTick(() => ++calculations.value); let raw_cell = raw_values[i][j].trim(); if (!raw_cell || raw_cell[0] != '=') return as_number(raw_cell); let user_code = raw_cell.substring(1); let code = transpile(user_code); try { // the constructor of a Function receives the body of a function as a string let fn = new Function(['computed_values'], `return ${code};`); return fn(computed_values); } catch (e) { return "ERROR"; } }); return computed_cell; }; for (let i = 0; i < rows.value; ++i) for (let j = 0; j < cols.value; ++j) computed_values[i][j] = computed_cell_generator(i, j);
Если мы поместим весь приведенный выше код в метод setup
, нам нужно будет вернуть {raw_values, computed_values, rows, cols, letters, calculations}
.
Ниже мы представляем полный компонент вместе с базовым пользовательским интерфейсом.
Код доступен на GitHub, и вы также можете ознакомиться с демо-версией.
<template> <div> <div>Calculations: {{ calculations }}</div> <table class="table" border="0"> <tr class="row"> <td></td> <td class="column" v-for="(_, j) in cols" :key="'header' + j" > {{ letters[j] }} </td> </tr> <tr class="row" v-for="(_, i) in rows" :key="i" > <td class="column"> {{ i + 1 }} </td> <td class="column" v-for="(__, j) in cols" :key="i + '-' + j" :class="{ column_selected: active(i, j), column_inactive: !active(i, j), }" @click="activate(i, j)" > <div v-if="active(i, j)"> <input :ref="'input' + i + '-' + j" v-model="raw_values[i][j]" @keydown.enter.prevent="ui_enter()" @keydown.esc="ui_esc()" /> </div> <div v-else v-html="computed_value_formatter(computed_values[i][j].value)"/> </td> </tr> </table> </div> </template> <script> import {ref, reactive, computed, watchEffect, toRefs, nextTick, onUpdated} from "vue"; export default { name: 'App', components: {}, data() { return { ui_editing_i: null, ui_editing_j: null, } }, methods: { get_dom_input(i, j) { return this.$refs['input' + i + '-' + j]; }, activate(i, j) { this.ui_editing_i = i; this.ui_editing_j = j; nextTick(() => this.get_dom_input(i, j).focus()); }, active(i, j) { return this.ui_editing_i === i && this.ui_editing_j === j; }, unselect() { this.ui_editing_i = null; this.ui_editing_j = null; }, computed_value_formatter(str) { if (str === undefined || str === null) return 'none'; return str; }, ui_enter() { if (this.ui_editing_i < this.rows - 1) this.activate(this.ui_editing_i + 1, this.ui_editing_j); else this.unselect(); }, ui_esc() { this.unselect(); }, }, setup() { /*** All the code we wrote above goes here. ***/ return {raw_values, computed_values, rows, cols, letters, calculations}; }, } </script> <style> .table { margin-left: auto; margin-right: auto; margin-top: 1ex; border-collapse: collapse; } .column { box-sizing: border-box; border: 1px lightgray solid; } .column:first-child { background: #f6f6f6; min-width: 3em; } .column:not(:first-child) { min-width: 4em; } .row:first-child { background: #f6f6f6; } #empty_first_cell { background: white; } .column_selected { border: 2px cornflowerblue solid !important; padding: 0px; } .column_selected input, .column_selected input:active, .column_selected input:focus { outline: none; border: none; } </style>
Как насчет реального использования?
Мы видели, как развязанная система реактивности Vue 3 обеспечивает не только более чистый код, но и более сложные реактивные системы, основанные на новом механизме реактивности Vue. Прошло примерно семь лет с тех пор, как был представлен Vue, и рост выразительности явно не пользовался большим спросом.
Пример с электронной таблицей — это прямая демонстрация того, на что сейчас способен Vue, и вы также можете проверить живую демонстрацию.
Но в качестве реального примера это несколько нишево. В каких ситуациях может пригодиться новая система? Наиболее очевидным вариантом использования реактивности по запросу может быть повышение производительности сложных приложений.

Во внешних приложениях, которые работают с большими объемами данных, накладные расходы на использование плохо продуманной реактивности могут негативно сказаться на производительности. Предположим, у нас есть приложение бизнес-панели, которое создает интерактивные отчеты о деловой активности компании. Пользователь может выбрать временной диапазон и добавить или удалить показатели эффективности в отчете. Некоторые индикаторы могут отображать значения, которые зависят от других индикаторов.
Одним из способов реализации генерации отчетов является монолитная структура. Когда пользователь изменяет входной параметр в интерфейсе, одно вычисляемое свойство, например, report_data
, обновляется. Вычисление этого вычисляемого свойства происходит по жестко запрограммированному плану: сначала вычисляются все независимые показатели эффективности, затем те, которые зависят только от этих независимых показателей и т. д.
Лучшая реализация будет отделять биты отчета и вычислять их независимо. В этом есть некоторые преимущества:
- Разработчику не нужно жестко кодировать план выполнения, что утомительно и чревато ошибками. Система реактивности Vue автоматически обнаружит зависимости.
- В зависимости от объема задействованных данных мы можем получить значительный прирост производительности, поскольку мы обновляем только те данные отчета, которые логически зависят от измененных входных параметров.
Если все показатели производительности, которые могут быть частью окончательного отчета, известны до того, как компонент Vue будет загружен, мы сможем реализовать предлагаемое разделение даже с Vue 2. В противном случае, если серверная часть является единственным источником достоверной информации (что обычно в случае с приложениями, управляемыми данными), или, если есть внешние поставщики данных, мы можем генерировать вычисляемые свойства по запросу для каждой части отчета.
Благодаря Vue 3 это теперь не только возможно, но и просто.