Vue 3 vs Vue 2: Key Differences and Development Impacts

Core Improvements in Vue 3

  • Performance Enhancements: Virtual DOM rewritten with static node skipping and dynamic node-only processing. Update performence improved by 1.3-2x, and SSR speed increased 2-3x.
  • Tree-shaking Support: Removes unused modules during build. Based on static analysis of ES6 imports to identify and eliminate unused code.
  • Fragment Support: Components can now have multiple root nodes, reducing unnecessary DOM nesting.
  • Teleport: Allows rendering parts of a compnoent's template outside its DOM hierarchy.
  • Suspense: Handles asynchronous dependencies in component trees, waiting for async components to resolve before rendering.
  • TypeScript Integration: Better native support for TypeScript in the core library and APIs.
  • Composition API: Introduces a more flexible API for organizing logic compared to the Options API.
  • Proxy-based Reactivity: Replaces Object.defineProperty with ES6 Proxy for better reactivity tarcking.

Development Differences

1. Setup Function

The <script setup> syntax provides a more concise way to use the Composition API in single-file components.

import { defineComponent } from 'vue'

export default defineComponent({
  props: {
    title: String
  },
  setup(props) {
    console.log(props.title)
  }
})

2. Lifecycle Hooks

Lifecycle hooks are imported from 'vue' and called directly:

import { onMounted, onUpdated } from 'vue'

onMounted(() => {
  // Component mounted
})

onUpdated(() => {
  // Component updated
})

Vue 2 Vue 3
beforeCreate setup()
created setup()
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated onUpdated
beforeDestroy onBeforeUnmount
destroyed onUnmounted
errorCaptured onErrorCaptured

3. Reactive Data

  • ref: Creates a reactive reference with a .value property
  • reactive: Creates a deep reactive proxy of an object
import { ref, reactive } from 'vue'

export default {
  setup() {
    const count = ref(0)
    const state = reactive({
      num: 0,
      list: [1, 2]
    })

    return { count, state }
  }
}

4. Computed Properties

Computed values return a read-only ref unless a setter is provided:

import { computed } from 'vue'

const count = ref(1)
const double = computed(() => count.value * 2)

// With setter
const countWithSetter = ref(1)
const plusOne = computed({
  get: () => countWithSetter.value + 1,
  set: val => {
    countWithSetter.value = val - 1
  }
})

5. Watchers

  • watchEffect: Runs immediately and tracks dependencies automatically
  • watch: Watches specific sources and runs callbacks
import { watch, watchEffect } from 'vue'

watchEffect(() => {
  console.log('Effect triggered')
})

watch(
  () => state.count,
  (newVal, oldVal) => {
    console.log('Count changed:', newVal)
  }
)

6. Template Refs

Refs can be used directly in templates to access DOM elements:

<template>
  <div ref="root"></div>
</template>

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

export default {
  setup() {
    const root = ref(null)
    
    onMounted(() => {
      console.log(root.value)
    })
    
    return { root }
  }
}
</script>

7. Router, Store, and App Initialization

Vue 3 uses a more modular approach:

// Vue 3
import { createApp } from 'vue'
import { createStore } from 'vuex'
import { createRouter } from 'vue-router'

const app = createApp(App)
const store = createStore({ /*...*/ })
const router = createRouter({ /*...*/ })

app.use(store)
app.use(router)
app.mount('#app')

// Vue 2
import Vue from 'vue'
import Vuex from 'vuex'
import VueRouter from 'vue-router'

Vue.use(Vuex)
Vue.use(VueRouter)

new Vue({
  store,
  router,
  render: h => h(App)
}).$mount('#app')

8. Custom Directives

Directives are registered with the app instance and have updated hook names:

import { createApp } from 'vue'

const app = createApp(App)

app.directive('custom', {
  beforeMount(el, binding) {
    // Similar to bind in Vue 2
  },
  mounted(el, binding) {
    // Similar to inserted in Vue 2
  },
  beforeUpdate(el, binding) {
    // New in Vue 3
  },
  updated(el, binding) {
    // Similar to componentUpdated in Vue 2
  },
  beforeUnmount(el, binding) {
    // New in Vue 3
  },
  unmounted(el, binding) {
    // Similar to unbind in Vue 2
  }
})

9. Emitting Events

In composition API, emit is obtained through the setup context:

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

const emit = defineEmits(['toggle'])

const isOpen = ref(false)

function toggle() {
  isOpen.value = !isOpen.value
  emit('toggle', isOpen.value)
}
</script>

Tags: Vue.js vue3 Composition API Reactivity System Design

Posted on Sun, 26 Jul 2026 16:30:24 +0000 by PHPdev