Ленивая инициализация — это техника, позволяющая откладывать создание
значений до момента их реального использования. В контексте Vue 3 и
Composition API это особенно актуально при работе с setup,
где некоторые вычисления могут быть дорогостоящими или зависеть от
состояния, которое ещё не сформировано.
В setup переменные обычно создаются с помощью
ref или reactive. При стандартной
инициализации значение создается сразу при вызове setup.
Ленивая инициализация реализуется через функцию-обёртку:
import { ref } from 'vue';
export default {
setup() {
const expensiveValue = ref(null);
function getExpensiveValue() {
if (expensiveValue.value === null) {
expensiveValue.value = computeExpensiveValue();
}
return expensiveValue.value;
}
function computeExpensiveValue() {
// сложные вычисления
return Array.from({ length: 10000 }, (_, i) => i).reduce((a, b) => a + b, 0);
}
return {
expensiveValue,
getExpensiveValue
};
}
}
В этом примере значение expensiveValue не вычисляется
сразу, а только при первом обращении через
getExpensiveValue. Такой подход снижает нагрузку на рендер
и экономит ресурсы.
computedcomputed свойства также могут использоваться для ленивой
инициализации. Они создаются только при первом обращении к их
значению:
import { ref, computed } from 'vue';
export default {
setup() {
const numbers = ref([1, 2, 3, 4, 5]);
const sum = computed(() => {
console.log('Вычисление суммы');
return numbers.value.reduce((a, b) => a + b, 0);
});
return {
numbers,
sum
};
}
}
До первого обращения к sum.value функция редуцирования
не выполнится. Этот принцип позволяет откладывать тяжелые вычисления до
момента реального использования данных.
При работе с API или длительными асинхронными операциями ленивую
инициализацию можно комбинировать с ref и
watchEffect или с функциями загрузки данных по
требованию:
import { ref } from 'vue';
export default {
setup() {
const data = ref(null);
async function loadData() {
if (!data.value) {
const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
data.value = await response.json();
}
return data.value;
}
return {
data,
loadData
};
}
}
Такой подход предотвращает ненужные сетевые запросы до тех пор, пока данные реально не понадобятся.
При написании тестов с Vue Test Utils ленивость играет важную роль,
так как позволяет уменьшить избыточное создание компонентов и данных.
Использование shallowMount вместе с функциями для ленивой
инициализации позволяет проверять поведение компонентов без
дорогостоящей загрузки всех зависимостей.
import { shallowMount } from '@vue/test-utils';
import MyComponent from '@/components/MyComponent.vue';
describe('MyComponent', () => {
it('лениво инициализирует данные', async () => {
const wrapper = shallowMount(MyComponent);
expect(wrapper.vm.expensiveValue).toBe(null);
const value = wrapper.vm.getExpensiveValue();
expect(value).toBeGreaterThan(0);
expect(wrapper.vm.expensiveValue).toBe(value);
});
});
Такой тест демонстрирует, что до вызова метода
getExpensiveValue значение не создается, а после вызова —
инициализируется корректно.
Ленивая инициализация является важным инструментом при работе с Composition API. Она сочетает в себе чистоту кода, эффективность и гибкость при управлении состоянием компонента и его вычисляемыми свойствами.