Advanced usage of Composition API
Core Concepts of Composition API
The Composition API is a new programming paradigm introduced in Vue 3, which organizes component logic in a functional way. Unlike the Options API, the Composition API groups related code together instead of scattering it across different option blocks.
import { ref, computed } from 'vue'
export default {
setup() {
const count = ref(0)
const double = computed(() => count.value * 2)
function increment() {
count.value++
}
return {
count,
double,
increment
}
}
}
Reactive State Management
In-Depth Usage of ref and reactive
ref
and reactive
are the two primary ways to create reactive data. ref
is suitable for primitive types and object references, while reactive
is specifically for objects.
import { ref, reactive } from 'vue'
const user = reactive({
name: 'Zhang San',
age: 25,
address: {
city: 'Beijing',
street: 'Chaoyang District'
}
})
const counter = ref(0)
// Accessing ref values requires .value
console.log(counter.value) // 0
// Reactive objects can be accessed directly
console.log(user.name) // Zhang San
Reactive Utility Functions
Vue provides a series of utility functions to handle reactive data:
import { isRef, unref, toRef, toRefs } from 'vue'
const count = ref(0)
console.log(isRef(count)) // true
// unref automatically unwraps refs
function useValue(maybeRef) {
return unref(maybeRef)
}
// Convert a reactive object's property to a ref
const userRef = toRef(user, 'name')
// Convert all properties of a reactive object to refs
const { name, age } = toRefs(user)
Composable Functions
Composable functions are the core abstraction mechanism of the Composition API, allowing us to extract reusable logic into separate functions.
Creating Custom Composable Functions
// useMouse.js
import { ref, onMounted, onUnmounted } from 'vue'
export function useMouse() {
const x = ref(0)
const y = ref(0)
function update(event) {
x.value = event.pageX
y.value = event.pageY
}
onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))
return { x, y }
}
// Usage in a component
import { useMouse } from './useMouse'
export default {
setup() {
const { x, y } = useMouse()
return { x, y }
}
}
Composable Functions with Parameters
// useFetch.js
import { ref } from 'vue'
export function useFetch(url) {
const data = ref(null)
const error = ref(null)
const loading = ref(false)
async function fetchData() {
loading.value = true
try {
const response = await fetch(url)
data.value = await response.json()
} catch (err) {
error.value = err
} finally {
loading.value = false
}
}
fetchData()
return { data, error, loading, retry: fetchData }
}
Advanced Usage of Lifecycle Hooks
The Composition API provides a more flexible way to manage lifecycles:
import { onMounted, onUpdated, onUnmounted } from 'vue'
export default {
setup() {
onMounted(() => {
console.log('Component mounted')
})
onUpdated(() => {
console.log('Component updated')
})
onUnmounted(() => {
console.log('Component unmounted')
})
}
}
Multiple Hooks with the Same Name
The Composition API allows registering multiple lifecycle hooks with the same name, which will be called in the order they were registered:
setup() {
onMounted(() => console.log('First mounted hook'))
onMounted(() => console.log('Second mounted hook'))
}
In-Depth Usage of Dependency Injection
provide
and inject
enable cross-level component communication:
// Ancestor component
import { provide, ref } from 'vue'
export default {
setup() {
const theme = ref('dark')
provide('theme', theme)
return {
theme
}
}
}
// Descendant component
import { inject } from 'vue'
export default {
setup() {
const theme = inject('theme', 'light') // Default value 'light'
return {
theme
}
}
}
Reactive Injection
// Provide a reactive value
const counter = ref(0)
provide('counter', counter)
// Inject and maintain reactivity
const injectedCounter = inject('counter')
Template Refs and Component Refs
In the Composition API, DOM elements or component instances are accessed via ref
:
import { ref, onMounted } from 'vue'
export default {
setup() {
const inputRef = ref(null)
onMounted(() => {
inputRef.value.focus()
})
return {
inputRef
}
},
template: `<input ref="inputRef">`
}
Exposing Component Methods
Child components can explicitly expose methods using expose
:
// Child component
import { ref } from 'vue'
export default {
setup(props, { expose) {
const count = ref(0)
function increment() {
count.value++
}
expose({
increment
})
return {
count
}
}
}
// Parent component
const childRef = ref(null)
function callChildMethod() {
childRef.value.increment()
}
Render Functions and JSX
The Composition API allows direct use of render functions:
import { h, ref } from 'vue'
export default {
setup() {
const count = ref(0)
return () => h('div', [
h('button', {
onClick: () => count.value++
}, 'Increment'),
h('span', `Current count: ${count.value}`)
])
}
}
JSX Support
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
return () => (
<div>
<button onClick={() => count.value++}>Increment</button>
<span>Current count: {count.value}</span>
</div>
)
}
}
Custom Directives
Creating custom directives in the Composition API:
import { directive } from 'vue'
const vFocus = {
mounted(el) {
el.focus()
}
}
// Usage
export default {
directives: {
focus: vFocus
},
setup() {
return {}
}
}
Global Directives
// main.js
import { createApp } from 'vue'
const app = createApp(App)
app.directive('focus', {
mounted(el) {
el.focus()
}
})
Performance Optimization Techniques
Computed Property Caching
import { computed, ref } from 'vue'
export default {
setup() {
const firstName = ref('Zhang')
const lastName = ref('San')
const fullName = computed(() => `${firstName.value}${lastName.value}`)
return {
fullName
}
}
}
Debouncing and Throttling
import { ref } from 'vue'
import { debounce } from 'lodash-es'
export default {
setup() {
const searchQuery = ref('')
const debouncedSearch = debounce(() => {
console.log('Search:', searchQuery.value)
}, 500)
function onInput() {
debouncedSearch()
}
return {
searchQuery,
onInput
}
}
}
TypeScript Integration
The Composition API integrates well with TypeScript:
import { ref, computed } from 'vue'
interface User {
name: string
age: number
}
export default {
setup() {
const user = ref<User>({
name: 'Zhang San',
age: 25
})
const nextYearAge = computed(() => user.value.age + 1)
return {
user,
nextYearAge
}
}
}
Type Inference
import { ref } from 'vue'
const count = ref(0) // Inferred as Ref<number>
count.value = '1' // Type error
State Management Integration
The Composition API can easily integrate with state management libraries like Pinia:
// store/counter.js
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
}),
actions: {
increment() {
this.count++
}
}
})
// Usage in a component
import { useCounterStore } from '@/stores/counter'
export default {
setup() {
const counter = useCounterStore()
return {
counter
}
}
}
Async Components and Suspense
The Composition API supports async components:
import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent(() =>
import('./components/AsyncComponent.vue')
)
export default {
components: {
AsyncComp
},
setup() {
return {}
}
}
Suspense Integration
<template>
<Suspense>
<template #default>
<AsyncComponent />
</template>
<template #fallback>
<div>Loading...</div>
</template>
</Suspense>
</template>
<script>
import { defineAsyncComponent } from 'vue'
export default {
components: {
AsyncComponent: defineAsyncComponent(() =>
import('./AsyncComponent.vue')
)
}
}
</script>
Custom Composition API Libraries
Organizing multiple composable functions into a library:
// composables/index.js
export * from './useMouse'
export * from './useFetch'
export * from './useLocalStorage'
// Usage in a component
import { useMouse, useFetch } from '@/composables'
export default {
setup() {
const { x, y } = useMouse()
const { data } = useFetch('/api/data')
return {
x,
y,
data
}
}
}
Reactive CSS Variables
The Composition API can dynamically generate CSS variables:
import { ref, watchEffect } from 'vue'
export default {
setup() {
const themeColor = ref('#42b983')
watchEffect(() => {
document.documentElement.style.setProperty(
'--theme-color',
themeColor.value
)
})
return {
themeColor
}
}
}
Server-Side Rendering (SSR) Support
Special handling for the Composition API in SSR environments:
import { ref, onServerPrefetch } from 'vue'
import { fetchData } from './api'
export default {
setup() {
const data = ref(null)
onServerPrefetch(async () => {
data.value = await fetchData()
})
return {
data
}
}
}
Debugging Techniques
The Composition API provides debugging tools:
import { debug } from 'vue'
export default {
setup() {
const count = ref(0)
debug(count) // Output reactive data changes in the console
return {
count
}
}
}
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn