Композиция в Vue 3

Vue 3 представляет новый способ организации кода с помощью Composition API. Это не замена Options API, а альтернатива, предоставляющая более гибкие и мощные возможности для создания компонентов. Composition API позволяет лучше структурировать и разделять логику в компонентах, что особенно важно для больших приложений с сложной архитектурой.

Использование setup() метода

Основной элемент Composition API — это метод setup(), который заменяет привычные данные, методы и вычисляемые свойства из Options API. Этот метод вызывается при создании компонента и служит местом, где можно объявить состояние, методы, вычисляемые значения и прочие элементы, необходимые компоненту.

Пример простого компонента с setup():

<template>
  <div>{{ message }}</div>
  <button @click="increment">Increment</button>
</template>

<script>
import { ref } from 'vue';

export default {
  setup() {
    const message = ref('Hello, Vue 3!');
    const count = ref(0);

    function increment() {
      count.value++;
      message.value = `Count: ${count.value}`;
    }

    return { message, increment };
  }
}
</script>

В этом примере:

  • ref() используется для создания реактивных данных.
  • Все объявленные переменные и функции возвращаются из setup() и становятся доступными в шаблоне компонента.

Рефы и реактивные данные

Основной принцип работы Composition API заключается в управлении состоянием компонента через реактивные данные. Для этого в Vue 3 появились два ключевых объекта: ref и reactive.

ref()

ref() используется для создания реактивных примитивных данных (строки, числа, булевы значения). Он возвращает объект, содержащий свойство .value, через которое осуществляется доступ к значению.

Пример использования ref():

import { ref } from 'vue';

const counter = ref(0);
counter.value++;  // изменяем значение

reactive()

reactive() используется для создания реактивных объектов и массивов. В отличие от ref(), который работает только с примитивами, reactive() может использоваться для работы с более сложными структурами данных.

Пример использования reactive():

import { reactive } from 'vue';

const state = reactive({
  count: 0,
  name: 'Vue 3'
});

state.count++;  // изменяем свойство объекта

Разница между ref() и reactive()

Основное отличие заключается в том, что:

  • ref() применяется для простых типов данных (строки, числа, булевы значения).
  • reactive() используется для объектов и массивов.

При этом объекты, возвращаемые reactive(), автоматически оборачиваются в реактивный объект, что позволяет работать с ними как с обычными объектами, не используя .value.

Механизм вычисляемых свойств — computed()

Vue 3 также предоставляет механизм вычисляемых свойств через computed(). Эти свойства являются реактивными и могут зависеть от других реактивных данных. Они автоматически пересчитываются при изменении зависимостей.

Пример использования computed():

import { computed, ref } from 'vue';

const count = ref(0);
const doubled = computed(() => count.value * 2);

count.value = 5;
console.log(doubled.value); // 10

В этом примере doubled является вычисляемым свойством, которое автоматически пересчитывается каждый раз, когда меняется count.

Управление жизненным циклом компонента

В Vue 3 также появились новые способы работы с жизненным циклом компонента через Composition API. Для этого в setup() можно использовать специальные функции:

  • onMounted()
  • onUpdated()
  • onUnmounted()
  • onBeforeMount()
  • onBeforeUpdate()
  • onBeforeUnmount()

Пример использования жизненного цикла:

import { ref, onMounted, onUnmounted } from 'vue';

export default {
  setup() {
    const count = ref(0);

    onMounted(() => {
      console.log('Компонент смонтирован');
    });

    onUnmounted(() => {
      console.log('Компонент удален');
    });

    return { count };
  }
}

Эти функции позволяют выполнять действия при монтировании компонента, его обновлении и удалении.

Работа с watch() и watchEffect()

Vue 3 предоставляет два механизма для наблюдения за изменениями данных: watch() и watchEffect().

watch()

watch() используется для отслеживания конкретных реактивных данных и выполнения побочных эффектов при их изменении.

Пример использования watch():

import { ref, watch } from 'vue';

const count = ref(0);

watch(count, (newValue, oldValue) => {
  console.log(`Значение изменилось с ${oldValue} на ${newValue}`);
});

count.value = 1;  // Лог: Значение изменилось с 0 на 1

watchEffect()

watchEffect() позволяет отслеживать изменения всех реактивных данных, использующихся внутри переданной функции. Это упрощает процесс отслеживания зависимостей, так как Vue автоматически определяет, какие данные влияют на функцию.

Пример использования watchEffect():

import { ref, watchEffect } from 'vue';

const count = ref(0);

watchEffect(() => {
  console.log(`Текущее значение: ${count.value}`);
});

count.value = 1;  // Лог: Текущее значение: 1

watchEffect() автоматически отслеживает все использующиеся внутри нее реактивные данные и обновляется при их изменении.

Расширение функциональности с помощью композиционных функций

Одним из больших преимуществ Composition API является возможность создания композиционных функций, которые позволяют инкапсулировать повторяющийся код и использовать его в разных компонентах. Эти функции могут содержать состояние, методы и другие реактивные элементы.

Пример композиционной функции:

import { ref } from 'vue';

function useCounter() {
  const count = ref(0);

  const increment = () => count.value++;
  const decrement = () => count.value--;

  return { count, increment, decrement };
}

Теперь эту композиционную функцию можно использовать в разных компонентах:

<template>
  <div>
    <p>{{ count }}</p>
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
  </div>
</template>

<script>
import { useCounter } from './useCounter';

export default {
  setup() {
    const { count, increment, decrement } = useCounter();
    return { count, increment, decrement };
  }
}
</script>

Такой подход позволяет создавать модульный и повторно используемый код.

Заключение

Composition API в Vue 3 предоставляет гибкость и удобство при создании компонентов, улучшая структуру кода, его повторное использование и тестируемость. Возможности работы с реактивными данными, вычисляемыми свойствами, жизненным циклом и наблюдением за изменениями позволяют создавать более мощные и легко поддерживаемые приложения.