Fading Coder

One Final Commit for the Last Sprint

Home > Notes > Content

Reactivity and Architectural Updates in Vue 3

Notes 2

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

Related Articles

Designing Alertmanager Templates for Prometheus Notifications

How to craft Alertmanager templates to format alert messages, improving clarity and presentation. Alertmanager uses Go’s text/template engine with additional helper functions. Alerting rules referenc...

Deploying a Maven Web Application to Tomcat 9 Using the Tomcat Manager

Tomcat 9 does not provide a dedicated Maven plugin. The Tomcat Manager interface, however, is backward-compatible, so the Tomcat 7 Maven Plugin can be used to deploy to Tomcat 9. This guide shows two...

Skipping Errors in MySQL Asynchronous Replication

When a replica halts because the SQL thread encounters an error, you can resume replication by skipping the problematic event(s). Two common approaches are available. Methods to Skip Errors 1) Skip a...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.