Vue 3.0 주요 특징 및 변경사항

Posted by Albert 67Day 9Hour 26Min 17Sec ago [2025-12-01]

1. Composition API

Vue 3의 가장 큰 변화로, 로직을 재사용 가능한 함수로 구성할 수 있습니다.

// Vue 2 Options API
export default {
  data() {
    return {
      count: 0
    }
  },
  methods: {
    increment() {
      this.count++
    }
  }
}

// Vue 3 Composition API
import { ref } from 'vue'

export default {
  setup() {
    const count = ref(0)
    const increment = () => {
      count.value++
    }
    
    return {
      count,
      increment
    }
  }
}

2. 반응성 시스템 개선

Proxy 기반의 새로운 반응성 시스템으로 성능이 향상되었습니다.

import { reactive, ref, computed } from 'vue'

export default {
  setup() {
    // ref: 기본 타입용
    const count = ref(0)
    
    // reactive: 객체용
    const state = reactive({
      name: 'Vue 3',
      version: '3.0'
    })
    
    // computed: 계산된 속성
    const doubleCount = computed(() => count.value * 2)
    
    return { count, state, doubleCount }
  }
}

3. setup() 함수

컴포넌트의 진입점으로, Composition API를 사용하는 핵심 함수입니다.

import { ref, onMounted, watch } from 'vue'

export default {
  props: ['title'],
  setup(props, context) {
    const message = ref('Hello')
    
    // 생명주기 훅
    onMounted(() => {
      console.log('컴포넌트가 마운트되었습니다')
    })
    
    // watch를 통한 반응성 추적
    watch(() => props.title, (newVal, oldVal) => {
      console.log(`제목이 ${oldVal}에서 ${newVal}로 변경됨`)
    })
    
    // context.emit으로 이벤트 발생
    const handleClick = () => {
      context.emit('custom-event', message.value)
    }
    
    return {
      message,
      handleClick
    }
  }
}

4. Teleport (Portal)

DOM 구조와 상관없이 특정 위치에 컴포넌트를 렌더링할 수 있습니다.

<template>
  <div>
    <button @click="showModal = true">모달 열기</button>
    
    <!-- body 태그로 텔레포트 -->
    <Teleport to="body">
      <div v-if="showModal" class="modal">
        <p>모달 내용</p>
        <button @click="showModal = false">닫기</button>
      </div>
    </Teleport>
  </div>
</template>

<script>
import { ref } from 'vue'

export default {
  setup() {
    const showModal = ref(false)
    return { showModal }
  }
}
</script>

5. Fragments (다중 루트 노드)

Vue 3에서는 여러 개의 루트 노드를 가질 수 있습니다.

<template>
  <!-- Vue 2에서는 에러, Vue 3에서는 정상 동작 -->
  <header>헤더</header>
  <main>메인 컨텐츠</main>
  <footer>푸터</footer>
</template>

6. Suspense

비동기 컴포넌트를 처리할 때 로딩 상태를 쉽게 관리할 수 있습니다.

<template>
  <Suspense>
    <!-- 비동기 컴포넌트 -->
    <template 'default>
      <AsyncComponent />
    </template>
    
    <!-- 로딩 중 표시될 내용 -->
    <template 'fallback>
      <div>로딩 중...</div>
    </template>
  </Suspense>
</template>

<script>
import { defineAsyncComponent } from 'vue'

export default {
  components: {
    AsyncComponent: defineAsyncComponent(() =>
      import('./AsyncComponent.vue')
    )
  }
}
</script>

7. provide/inject 개선

컴포넌트 트리 전체에 데이터를 공유할 수 있습니다.

// 부모 컴포넌트
import { provide, ref } from 'vue'

export default {
  setup() {
    const theme = ref('dark')
    
    provide('theme', theme)
    
    const changeTheme = () => {
      theme.value = theme.value === 'dark' ? 'light' : 'dark'
    }
    
    return { changeTheme }
  }
}

// 자식 컴포넌트 (깊은 하위 컴포넌트 가능)
import { inject } from 'vue'

export default {
  setup() {
    const theme = inject('theme')
    
    return { theme }
  }
}

8. Emits 옵션

컴포넌트가 발생시킬 이벤트를 명시적으로 선언할 수 있습니다.

<template>
  <button @click="handleClick">클릭</button>
</template>

<script>
export default {
  emits: ['submit', 'cancel'],
  setup(props, { emit }) {
    const handleClick = () => {
      emit('submit', { data: 'example' })
    }
    
    return { handleClick }
  }
}
</script>

9. Script Setup 구문 (Vue 3.2+)

더 간결한 문법으로 Composition API를 사용할 수 있습니다.

<template>
  <div>
    <h1>{{ title }}</h1>
    <p>카운트: {{ count }}</p>
    <button @click="increment">증가</button>
  </div>
</template>

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

// props 정의
const props = defineProps({
  title: String
})

// emits 정의
const emit = defineEmits(['update'])

// 반응형 데이터
const count = ref(0)

// 메서드
const increment = () => {
  count.value++
  emit('update', count.value)
}

// computed
const doubleCount = computed(() => count.value * 2)
</script>

10. 생명주기 훅

Composition API에서의 생명주기 훅 사용법입니다.

import { 
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted
} from 'vue'

export default {
  setup() {
    onBeforeMount(() => {
      console.log('마운트 전')
    })
    
    onMounted(() => {
      console.log('마운트 완료')
    })
    
    onBeforeUpdate(() => {
      console.log('업데이트 전')
    })
    
    onUpdated(() => {
      console.log('업데이트 완료')
    })
    
    onBeforeUnmount(() => {
      console.log('언마운트 전')
    })
    
    onUnmounted(() => {
      console.log('언마운트 완료')
    })
  }
}

11. TypeScript 지원 강화

import { defineComponent, ref, PropType } from 'vue'

interface User {
  id: number
  name: string
}

export default defineComponent({
  props: {
    user: {
      type: Object as PropType<User>,
      required: true
    }
  },
  setup(props) {
    const count = ref<number>(0)
    const message = ref<string>('Hello')
    
    return {
      count,
      message
    }
  }
})

12. Composables (재사용 가능한 로직)

// composables/useCounter.js
import { ref, computed } from 'vue'

export function useCounter(initialValue = 0) {
  const count = ref(initialValue)
  
  const increment = () => count.value++
  const decrement = () => count.value--
  const reset = () => count.value = initialValue
  
  const doubleCount = computed(() => count.value * 2)
  
  return {
    count,
    increment,
    decrement,
    reset,
    doubleCount
  }
}

// 컴포넌트에서 사용
import { useCounter } from './composables/useCounter'

export default {
  setup() {
    const { count, increment, decrement, doubleCount } = useCounter(10)
    
    return {
      count,
      increment,
      decrement,
      doubleCount
    }
  }
}

Vue 3.0의 주요 장점

  1. 성능 향상: 번들 크기 감소, 렌더링 속도 개선
  2. 더 나은 TypeScript 지원
  3. Tree-shaking 지원: 사용하지 않는 기능 제거
  4. 향상된 코드 재사용성: Composition API를 통한 로직 공유
  5. 유지보수성 개선: 더 명확한 코드 구조

Vue 3는 Vue 2의 모든 장점을 유지하면서도 현대적인 웹 개발 요구사항을 충족시키는 강력한 프레임워크로 발전했습니다.




LIST

Copyright © 2014 visionboy.me All Right Reserved.