Reactivity and Architectural Updates in Vue 3
Reactivity System Overhaul
Vue 2's Approach
Vue 2 implements two-way data binding using Object.defineProperty() to intercept property access combined with a publish-subscribe pattern.
const vm = new Vue({
data: { counter: 0 },
// Internal transformation creates getters/setters
// counter becomes reactive through interception
methods: {
increment() { this.counter++ } // Triggers setter
}
})
Limitations:
- Only properties present during instance creation become reactive
- Newly added properties lack reactivity
- Array index modifications don't trigger updates
- Direct array element assignment bypasses reactivity
Vue 3's Proxy-Based System
Vue 3 employs ES6 Proxies to create comprehensive reactivity wrappers around data objects.
const reactiveArray = new Proxy([10, 20, 30], {
get(target, property) {
console.log(`Reading index ${property}`)
return target[property]
},
set(target, property, value) {
console.log(`Setting index ${property} to ${value}`)
target[property] = value
return true
}
})
const element = reactiveArray[2] // Logs: Reading index 2
reactiveArray[1] = 99 // Logs: Setting index 1 to 99
Proxy advantages include full property coverage and array support, though browser compatibility considerations remain.
Project Structure Updates
Application Initialization
Vue 3 replaces the Vue constructor with factory functions.
import { createApp } from 'vue'
import RootComponent from './App.vue'
import router from './router'
import store from './store'
// Modular imports replace prototype extensions
import axios from 'axios'
axios.defaults.baseURL = 'https://api.example.com'
createApp(RootComponent)
.use(router)
.use(store)
.mount('#app')
Composition API Setup
The setup() function serves as the entry point for component logic.
<template>
<button @click="increase">{{ count }}</button>
</template>
<script>
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup() {
const count = ref(0)
const username = ref('')
const increase = () => { count.value++ }
return { count, username, increase }
}
})
</script>
Structured Reactivity with toRefs
<script>
import { defineComponent, ref, toRefs } from 'vue'
export default defineComponent({
setup() {
const state = ref({
score: 100,
items: ['apple', 'banana'],
user: { id: 1, name: 'Alex' }
})
const { score, items, user } = toRefs(state.value)
const operations = {
updateScore() { score.value += 10 },
modifyItems() { items.value.push('orange') }
}
return { ...toRefs(state.value), ...operations }
}
})
</script>
Enhanced Watch Functionality
Multiple independent watchers can monitor different reactive sources.
<script>
import { defineComponent, ref, watch, toRefs } from 'vue'
export default defineComponent({
setup() {
const data = ref({
temperature: 25,
readings: [12, 15, 18]
})
const { temperature, readings } = toRefs(data.value)
watch(temperature, (newTemp, oldTemp) => {
console.log(`Temperature changed from ${oldTemp} to ${newTemp}`)
})
watch(readings, (newReadings, oldReadings) => {
console.log('Readings updated:', newReadings)
})
return { temperature, readings }
}
})
</script>
Custom Directives
Global Directive Registration
const app = createApp(App)
app.directive('auto-focus', {
mounted(element) {
element.focus()
}
})
app.mount('#app')
Component-Local Directives
<script>
import { defineComponent } from 'vue'
export default defineComponent({
directives: {
'highlight': {
mounted(el) {
el.style.backgroundColor = 'yellow'
}
}
}
})
</script>
Computed Properties
<script>
import { defineComponent, ref, computed, toRefs } from 'vue'
export default defineComponent({
setup() {
const inventory = ref({
products: [
{ id: 1, title: 'Laptop', cost: 800, quantity: 5 },
{ id: 2, title: 'Mouse', cost: 25, quantity: 20 },
{ id: 3, title: 'Keyboard', cost: 45, quantity: 15 }
]
})
const { products } = toRefs(inventory.value)
const calculations = {
totalValue: computed(() => {
return products.value.reduce((sum, item) => {
return sum + (item.cost * item.quantity)
}, 0)
})
}
return { products, ...calculations }
}
})
</script>
Global Component Registration
import { createApp } from 'vue'
import App from './App.vue'
import NavigationBar from './components/NavigationBar.vue'
const app = createApp(App)
app.component('nav-bar', NavigationBar)
app.mount('#app')
Property Definitions
Component props maintain similar functionality with improved TypeScript integration and validation options.
Additional Updates
- Teleport component for DOM placement control
- Fragments supporting multiple root nodes
- Suspense for asynchronous component handling
- Emits option for explicit event declaration
- Lifecycle hook renaming (beforeDestroy → beforeUnmount)
- Performance optimizations through tree-shaking