Vue Options Api Best Practices

Vue Options Api Best Practices

Vue Options Api Best Practices automation and integration

Category: development Source: vuejs-ai/skills

Vue Options API Best Practices is a community skill for writing Vue components using the Options API, covering component structure, computed properties, watchers, lifecycle hooks, and mixins for Vue 3 Options API development.

What Is This?

Overview

Vue Options API Best Practices provides patterns for building Vue components using the traditional Options API approach. It covers component organization with data, methods, computed, and watch options for structured component logic, computed properties with getters and setters for derived reactive state, watchers with immediate, deep, and flush options for side effect handling, lifecycle hooks for initialization, DOM access, and cleanup operations, and mixin composition for sharing logic across components. The skill enables developers working with Options API codebases to follow consistent patterns that maintain readability and prevent common pitfalls.

Who Should Use This

This skill serves Vue developers maintaining existing Options API codebases, teams that prefer the Options API organization for component logic, and engineers learning Vue who find the Options API more approachable than Composition API.

Why Use It?

Problems It Solves

Large Options API components become difficult to navigate when related logic is scattered across data, methods, and watch sections. Watchers that trigger API calls without debouncing create excessive network requests. Mixins with overlapping property names cause silent conflicts that are hard to debug. Lifecycle hook ordering confusion leads to DOM access before elements are rendered.

Core Highlights

Component structure organizes related logic within Options API sections consistently. Computed properties cache derived values and update reactively on dependency changes. Watchers respond to data changes with configurable timing and depth. Lifecycle hooks execute code at precise points in the component lifecycle.

How to Use It?

Basic Usage

<script>
export default {
  name: 'UserProfile',
  props: {
    userId: {
      type: String,
      required: true,
    },
  },
  data() {
    return {
      user: null,
      loading: false,
      error: null,
    };
  },
  computed: {
    fullName() {
      if (!this.user) return '';
      return `${this.user.firstName}`
        + ` ${this.user.lastName}`;
    },
    initials() {
      return this.fullName
        .split(' ')
        .map((n) => n[0])
        .join('')
        .toUpperCase();
    },
  },
  watch: {
    userId: {
      handler: 'fetchUser',
      immediate: true,
    },
  },
  methods: {
    async fetchUser() {
      this.loading = true;
      this.error = null;
      try {
        const res = await fetch(
          `/api/users/${this.userId}`);
        this.user = await res.json();
      } catch (e) {
        this.error = e.message;
      } finally {
        this.loading = false;
      }
    },
  },
};
</script>

Real-World Examples

<script>
export default {
  name: 'SearchFilter',
  props: {
    items: {
      type: Array,
      default: () => [],
    },
  },
  data() {
    return {
      query: '',
      sortField: 'name',
      sortOrder: 'asc',
    };
  },
  computed: {
    filtered() {
      const q = this.query
        .toLowerCase();
      return this.items
        .filter((item) =>
          item.name.toLowerCase()
            .includes(q))
        .sort((a, b) => {
          const val = a[this.sortField]
            .localeCompare(
              b[this.sortField]);
          return this.sortOrder ===
            'asc' ? val : -val;
        });
    },
    resultCount() {
      return this.filtered.length;
    },
  },
  watch: {
    query(newVal, oldVal) {
      this.$emit(
        'search-change', {
          query: newVal,
          count: this.resultCount,
        });
    },
  },
  methods: {
    toggleSort(field) {
      if (this.sortField === field) {
        this.sortOrder =
          this.sortOrder === 'asc'
            ? 'desc' : 'asc';
      } else {
        this.sortField = field;
        this.sortOrder = 'asc';
      }
    },
    reset() {
      this.query = '';
      this.sortField = 'name';
      this.sortOrder = 'asc';
    },
  },
};
</script>

Advanced Tips

Use computed properties instead of methods for values that depend on reactive data, as computed caches results until dependencies change. Set watcher flush to post when you need to access updated DOM elements after a reactive change. Use provide/inject as an alternative to mixins for sharing logic without naming conflicts.

When to Use It?

Use Cases

Build a search interface with computed filtered results that update as users type. Create a form component with validation watchers that trigger on field changes. Maintain a legacy Vue application where gradual migration to Composition API is planned.

Related Topics

Vue.js component patterns, reactive programming, computed properties, lifecycle management, and mixin composition.

Important Notes

Requirements

Vue 3 which supports both Options and Composition API. JavaScript or TypeScript project with Vue SFC support. Understanding of Vue reactivity for data and computed properties.

Usage Recommendations

Do: use computed properties for derived values instead of manually updating data in watchers. Set immediate: true on watchers that should run on component creation. Keep components focused by extracting reusable logic into composables or mixins.

Don't: mutate props directly inside components when computed setters or emitted events handle the pattern correctly. Use deep watchers on large objects when watching specific nested paths is sufficient. Create mixins with generic names that are likely to conflict with component properties.

Limitations

Options API scatters related logic across different sections, making large components harder to follow. Mixins create implicit dependencies that are not visible in component code. TypeScript support in Options API is less ergonomic than in Composition API with defineComponent.