阿里云主机折上折
  • 微信号
Current Site:Index > Composition API component writing style

Composition API component writing style

Author:Chuan Chen 阅读数:16078人阅读 分类: Vue.js

The Composition API is a new component writing approach introduced in Vue 3, which organizes code by logical concerns, addressing the issue of scattered code in complex components with the Options API. Below is a detailed explanation covering core concepts, practical applications, and comparative analysis.

Core Concepts and Basic Usage

The core of the Composition API is the setup() function, which serves as the entry point for compositional logic. Unlike the Options API, all reactive data, computed properties, and methods are declared here:

<script setup>
import { ref, computed } from 'vue'

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

function increment() {
  count.value++
}
</script>

<template>
  <button @click="increment">{{ count }} x2 = {{ doubleCount }}</button>
</template>

Reactive data is created using ref() or reactive():

  • ref is used for primitive types, accessed via .value
  • reactive is used for object types, with direct property access

Logic Reuse and Composable Functions

Composable functions are the primary way to reuse logic. A typical composable encapsulates specific functionality and returns reactive data:

// useCounter.js
import { ref } from 'vue'

export function useCounter(initialValue = 0) {
  const count = ref(initialValue)
  
  function increment(step = 1) {
    count.value += step
  }

  return { count, increment }
}

Using composables in components:

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

const { count, increment } = useCounter(10)
</script>

Lifecycle Hook Usage

The Composition API provides corresponding lifecycle hook functions prefixed with on:

<script setup>
import { onMounted, onUnmounted } from 'vue'

onMounted(() => {
  console.log('Component mounted')
  const timer = setInterval(() => {
    console.log('Executing timer task')
  }, 1000)
  
  onUnmounted(() => {
    clearInterval(timer)
  })
})
</script>

Comparison with Options API

  1. Code Organization
// Options API
export default {
  data() {
    return { count: 0 }
  },
  methods: {
    increment() { this.count++ }
  },
  computed: {
    double() { return this.count * 2 }
  }
}

// Composition API
const count = ref(0)
const double = computed(() => count.value * 2)
function increment() { count.value++ }
  1. TypeScript Support The Composition API naturally supports type inference:
interface User {
  id: number
  name: string
}

const user = ref<User>({ id: 1, name: 'Alice' })

Advanced Patterns and Best Practices

  1. Props Handling
<script setup>
const props = defineProps({
  title: {
    type: String,
    required: true
  },
  likes: Number
})

// TypeScript version
const props = defineProps<{
  title: string
  likes?: number
}>()
</script>
  1. State Management Integration
// Using Pinia
import { useStore } from '@/stores/counter'

const store = useStore()
// Direct state modification
store.increment()
// Using computed properties
const double = computed(() => store.doubleCount)
  1. Async Operations Handling
<script setup>
import { ref } from 'vue'

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

async function fetchData() {
  loading.value = true
  try {
    const response = await fetch('/api/data')
    data.value = await response.json()
  } catch (err) {
    error.value = err
  } finally {
    loading.value = false
  }
}

// Immediate execution
fetchData()
</script>

Common Problem Solutions

  1. Reactivity Loss Issue
// Wrong approach: Destructuring loses reactivity
const { x, y } = reactive({ x: 1, y: 2 })

// Correct approach: Use toRefs
const state = reactive({ x: 1, y: 2 })
const { x, y } = toRefs(state)
  1. Template Refs
<template>
  <input ref="inputRef">
</template>

<script setup>
import { ref, onMounted } from 'vue'

const inputRef = ref(null)

onMounted(() => {
  inputRef.value.focus()
})
</script>
  1. Dependency Injection
// Ancestor component
import { provide } from 'vue'
provide('theme', 'dark')

// Descendant component
import { inject } from 'vue'
const theme = inject('theme', 'light') // Default value

Performance Optimization Techniques

  1. Computed Property Caching
const expensiveValue = computed(() => {
  // Complex calculation
  return heavyCalculation(items.value)
})
  1. watch Optimization
// Watch specific properties only
watch(
  () => obj.deep.nested.value,
  (newVal) => {
    console.log('Change:', newVal)
  },
  { immediate: true }
)

// Batch watching
watch([fooRef, barRef], ([foo, bar]) => {
  // Executes when foo or bar changes
})
  1. Shallow Reactivity
const shallowObj = shallowReactive({
  nested: { value: 1 } // Nested objects are not automatically reactive
})

Integration with Third-Party Libraries

  1. Chart Library Example
<script setup>
import { ref, onMounted, watch } from 'vue'
import * as echarts from 'echarts'

const chartRef = ref(null)
const chartInstance = ref(null)
const options = ref({ /* Chart configuration */ })

onMounted(() => {
  chartInstance.value = echarts.init(chartRef.value)
  chartInstance.value.setOption(options.value)
})

watch(options, (newVal) => {
  chartInstance.value?.setOption(newVal)
}, { deep: true })
</script>

<template>
  <div ref="chartRef" style="width: 600px; height: 400px;"></div>
</template>
  1. Animation Library Example
<script setup>
import { ref } from 'vue'
import gsap from 'gsap'

const boxRef = ref(null)

function animate() {
  gsap.to(boxRef.value, {
    x: 100,
    duration: 1,
    ease: 'power2.out'
  })
}
</script>

<template>
  <div ref="boxRef" @click="animate"></div>
</template>

Enterprise-Level Application Architecture

  1. Layered Architecture Example
src/
├── composables/
│   ├── useApi.ts
│   ├── useFormValidation.ts
│   └── usePagination.ts
├── components/
│   ├── BasePagination.vue
│   └── BaseModal.vue
└── views/
    ├── UserList.vue
    └── UserDetail.vue
  1. Global State Management
// stores/user.js
import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  state: () => ({
    users: [],
    currentUser: null
  }),
  actions: {
    async fetchUsers() {
      this.users = await api.getUsers()
    }
  }
})
  1. Route Control
<script setup>
import { useRouter } from 'vue-router'

const router = useRouter()

function navigateToUser(id) {
  router.push(`/user/${id}`)
}
</script>

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.