Composables: переиспользуемая логика

Учимся выносить реактивную логику из компонента в отдельную функцию-composable, чтобы переиспользовать её где угодно — главная суперсила Composition API.

Composable — функция, которая использует реактивность Vue (ref, computed, хуки) и возвращает состояние и методы для переиспользования в любом компоненте. По соглашению её имя начинается с use.

Зачем нужны composables

Допустим, логика счётчика (значение, увеличить, сбросить) нужна в трёх компонентах. Копировать её — плохо. Composition API позволяет вынести логику в обычную функцию и переиспользовать, не дублируя код. Это и есть главное преимущество подхода над Options API.

Пишем useCounter

Composable — это просто функция, которая внутри использует ref и возвращает то, что нужно компоненту:

<!-- composables/useCounter.js -->
<script>
import { ref } from 'vue'

export function useCounter(start = 0) {
  const count = ref(start)
  function increment() { count.value++ }
  function reset() { count.value = start }
  return { count, increment, reset }
}
</script>

Любой компонент вызывает её и получает готовую реактивную логику:

<template>
  <p>Счёт: {{ count }}</p>
  <button @click="increment">+1</button>
  <button @click="reset">Сброс</button>
</template>

<script setup>
import { useCounter } from './composables/useCounter'
const { count, increment, reset } = useCounter(10)
</script>

Ключевая мысль про независимость

Каждый вызов useCounter() создаёт своё состояние — composables не делят его между компонентами (если только не выносить ref наружу функции). Проверим это поведение обычным кодом:

function useCounter(start = 0) {
  let count = start;                       // у каждого вызова свой count
  return {
    increment: () => ++count,
    value: () => count,
  };
}

const a = useCounter(0);
const b = useCounter(100);

a.increment();
a.increment();
b.increment();

console.log("Счётчик A:", a.value());
console.log("Счётчик B:", b.value());

Вывод:

Счётчик A: 2
Счётчик B: 101

Видно: счётчики a и b независимы — каждый хранит своё состояние. Так же ведут себя и реальные composables на ref.

Соглашение об имени use

Имя composable принято начинать с use (useCounter, useFetch, useMouse). Это не требование синтаксиса, а соглашение сообщества — оно сразу говорит читателю: «это функция с реактивной логикой Vue, её зовут внутри setup».

Что обычно выносят в composables

  • useFetch — загрузка данных с состояниями loading/error.
  • useLocalStorage — синхронизация ref с localStorage.
  • useMouse — отслеживание позиции курсора.

Итог

  • Composable — функция с реактивной логикой, возвращающая состояние и методы.
  • Позволяет переиспользовать логику между компонентами без дублирования.
  • Каждый вызов создаёт независимое состояние.
  • Имя по соглашению начинается с use.
Проверьте себя
1. Что такое composable во Vue?
AВстроенный компонент Vue
BФункция с реактивной логикой (ref, computed, хуки), которую переиспользуют между компонентами
CСпособ стилизации компонента
DЗамена для пропсов
2. Почему имена composables начинают с use (useCounter, useFetch)?
AЭто обязательное требование компилятора Vue
BЭто соглашение сообщества, которое сразу обозначает функцию с реактивной логикой Vue
CИначе функция не будет реактивной
Duse ускоряет выполнение
3. Что произойдёт с состоянием, если вызвать один composable в двух компонентах?
AОба компонента разделят общее состояние
BКаждый вызов создаст своё независимое состояние (если ref не вынесен за пределы функции)
CVue выдаст ошибку
DВторой вызов перезапишет первый
Поддержать проект