Паттерны и best practices

В Vue.js компоненты — это строительные блоки интерфейса. Компонент должен быть атомарным, отвечать за конкретную функциональность, что повышает переиспользуемость и поддерживаемость кода. Важно разделять компоненты по принципу Single Responsibility Principle (SRP): один компонент — одна логическая задача.

Файловая структура компонентов должна быть логичной:

src/
 └─ components/
     ├─ BaseButton.vue
     ├─ UserCard.vue
     └─ Modal/
         ├─ Modal.vue
         └─ ModalHeader.vue

Базовые компоненты (BaseButton, BaseInput) используются в разных местах приложения и не зависят от контекста. Контейнерные компоненты (UserCard, Modal) объединяют базовые элементы и управляют состоянием.

Свойства и события

Props используются для передачи данных от родителя к дочернему компоненту. Рекомендуется всегда явно определять тип и обязательность пропса:

props: {
  title: {
    type: String,
    required: true
  },
  count: {
    type: Number,
    default: 0
  }
}

События через emit позволяют передавать данные вверх по иерархии:

this.$emit('update', newValue);

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

Управление состоянием

Для сложных приложений Vuex или Pinia являются стандартом. Основные паттерны работы с состоянием:

  • Модули: разделение состояния на логические части.
  • Геттеры: вычисляемые свойства состояния.
  • Действия: асинхронные операции, работа с API.
  • Мутации: синхронное изменение состояния.

Пример Pinia:

import { defineStore } from 'pinia';

export const useUserStore = defineStore('user', {
  state: () => ({
    users: [],
    loading: false
  }),
  getters: {
    userCount: (state) => state.users.length
  },
  actions: {
    async fetchUsers() {
      this.loading = true;
      this.users = await fetch('/api/users').then(res => res.json());
      this.loading = false;
    }
  }
});

Комбинирование Composition API и Options API

Composition API позволяет лучше структурировать логику компонентов, особенно при переиспользовании:

import { ref, computed } from 'vue';

export default {
  setup() {
    const count = ref(0);
    const doubled = computed(() => count.value * 2);

    function increment() {
      count.value++;
    }

    return { count, doubled, increment };
  }
}

Best practice: использовать Composition API для сложной логики, Options API — для простых компонентов, где структура ясна.

Директивы и реактивность

v-model обеспечивает двустороннее связывание данных. В Vue 3 можно использовать несколько моделей:

<CustomInput v-model:title="title" v-model:content="content" />

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

Асинхронные операции и эффектные паттерны

Для работы с API используют async/await внутри Composition API или методов компонента. Часто применяется паттерн загрузки с состоянием:

const loading = ref(false);
const data = ref(null);
const error = ref(null);

async function fetchData() {
  loading.value = true;
  try {
    data.value = await fetch('/api/data').then(res => res.json());
  } catch (e) {
    error.value = e;
  } finally {
    loading.value = false;
  }
}

Lazy loading компонентов и динамический импорт улучшают производительность:

const LazyComponent = defineAsyncComponent(() => import('./LazyComponent.vue'));

Паттерны организации событий и коммуникации

  • Provide/Inject: передача данных через иерархию компонентов без пропсов.
  • Event Bus: редко, но подходит для небольших проектов.
  • Custom Hooks: создание переиспользуемых функций логики с Composition API:
export function useCounter() {
  const count = ref(0);
  const increment = () => count.value++;
  return { count, increment };
}

Стилизация компонентов

Использование scoped стилей гарантирует изоляцию. Для больших приложений рекомендуется применять CSS Modules или utility-first подход (TailwindCSS). Важно избегать глобальных стилей без необходимости, чтобы не возникало конфликтов.

Тестирование и поддерживаемость

  • Unit-тесты компонентов с Vue Test Utils.
  • Snapshot-тесты для UI.
  • E2E-тесты через Cypress или Playwright.

Рекомендация: каждый компонент должен иметь хотя бы один unit-тест, особенно если он содержит сложную логику.

Итоговые паттерны

  1. Атомарные компоненты + SRP.
  2. Явные типы пропсов и событий.
  3. Pinia/Vuex для состояния, модульность и чистая архитектура.
  4. Composition API для переиспользуемой логики.
  5. Асинхронные паттерны с loading/error state.
  6. Ленивая загрузка и динамические импорты для оптимизации.
  7. Scoped стили и модульная CSS-структура.
  8. Тестирование как неотъемлемая часть процесса.

Эти паттерны формируют основу профессиональной разработки на Vue.js и обеспечивают масштабируемость и поддержку крупных проектов.