Now that Vue 3 is released, let’s dive deeper into the Composition API with practical examples you can use in real projects. I’ve been using the Composition API in production for several months via the Vue 2 plugin, and these patterns have proven invaluable.
Understanding Reactivity Fundamentals
The Composition API introduces two main reactive primitives: ref and reactive. Understanding when to use each is crucial.
import { ref, reactive, toRefs } from 'vue'
// ref - for primitives and replacing entire values
const count = ref(0)
const user = ref(null)
count.value++ // Access via .value
user.value = { name: 'John' } // Can replace entirely
// reactive - for objects you'll mutate
const state = reactive({
users: [],
currentPage: 1,
filters: { search: '', status: 'active' }
})
state.users.push(newUser) // Direct mutation, no .value
state.filters.search = 'John'
// toRefs - destructure reactive objects while keeping reactivity
const { users, currentPage } = toRefs(state)
// users.value is reactive
Building Reusable Composables
Composables are the heart of the Composition API. Here’s a real-world example for handling API calls with loading states, error handling, and caching:
// composables/useApi.js
import { ref, shallowRef } from 'vue'
export function useApi(fetcher) {
const data = shallowRef(null)
const error = ref(null)
const isLoading = ref(false)
async function execute(...args) {
isLoading.value = true
error.value = null
try {
data.value = await fetcher(...args)
return data.value
} catch (e) {
error.value = e
throw e
} finally {
isLoading.value = false
}
}
return {
data,
error,
isLoading,
execute
}
}
// Usage in component
import { useApi } from '@/composables/useApi'
import { userService } from '@/services/user'
export default {
setup() {
const { data: users, isLoading, error, execute: loadUsers } =
useApi(userService.getAll)
onMounted(loadUsers)
return { users, isLoading, error, loadUsers }
}
}
Composable for Local Storage
Here’s another practical composable for syncing state with localStorage:
// composables/useLocalStorage.js
import { ref, watch } from 'vue'
export function useLocalStorage(key, defaultValue) {
const stored = localStorage.getItem(key)
const value = ref(stored ? JSON.parse(stored) : defaultValue)
watch(value, (newValue) => {
localStorage.setItem(key, JSON.stringify(newValue))
}, { deep: true })
return value
}
// Usage - automatically persisted!
const theme = useLocalStorage('theme', 'light')
const recentSearches = useLocalStorage('searches', [])
Lifecycle Hooks in Composition API
Lifecycle hooks are imported and called directly in setup():
import { onMounted, onUnmounted, onUpdated, onBeforeUnmount } from 'vue'
export default {
setup() {
onMounted(() => {
console.log('Component mounted')
window.addEventListener('resize', handleResize)
})
onBeforeUnmount(() => {
window.removeEventListener('resize', handleResize)
})
// Can call multiple times - they all run
onMounted(() => {
console.log('Second onMounted')
})
}
}
Key Takeaways
- Use
reffor primitives and replaceable values,reactivefor objects you’ll mutate - Extract reusable logic into composable functions
- Composables can be composed together for complex functionality
- Lifecycle hooks are imported functions called within setup()
References
Discover more from C4: Container, Code, Cloud & Context
Subscribe to get the latest posts sent to your email.