Vue 3 ๊ฐ€๋ณ๊ฒŒ ํ›‘์–ด๋ณด๊ธฐ

๋“ค์–ด๊ฐ€๋ฉฐ

์•ˆ๋…•ํ•˜์„ธ์š” ์˜ค๋žœ๋งŒ์˜ ๊ธ€์ด๋„ค์š”. ์ตœ๊ทผ์— ์ƒˆ๋กœ์šด ํšŒ์‚ฌ๋กœ ์ด์งํ•˜๋ฉด์„œ ํฌ์ŠคํŒ… ์ค€๋น„ ๊ธฐ๊ฐ„์ด ๊ฝค ๊ธธ์–ด์ง„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋‹ค๋“ค ์ฝ”๋กœ๋‚˜๋Š” ์ž˜ ์ด๊ฒจ๋‚ด๊ณ  ๊ณ„์‹ ๊ฐ€์š”? ํ•˜๋ฃจ๋นจ๋ฆฌ ๋งˆ์Œ ํŽธํžˆ ๋ฐ–์„ ๋‚˜๊ฐˆ ์ˆ˜ ์žˆ๋Š” ๋‚ ์ด ์™”์œผ๋ฉด ์ข‹๊ฒ ๋„ค์š”.. ๐Ÿ˜„

์˜ค๋Š˜ ์ค€๋น„ํ•œ ๊ธ€์€ ๋‹ค๋“ค ์ด๋ฏธ ๋“ค์œผ์…จ์„ Vue.js์˜ ์‹ ๊ทœ ๋ฒ„์ „์— ๋Œ€ํ•œ ํฌ์ŠคํŒ…์ž…๋‹ˆ๋‹ค. ๋ทฐ ๊ณต์‹ ์‚ฌ์ดํŠธ์—์„œ ๋ทฐ 3 ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ํ™•์ธํ•˜์‹ค ์ˆ˜ ์žˆ๋Š”๋ฐ์š”. ์ด ์‚ฌ์ดํŠธ๋ฅผ ๋ชจ๋‘ ํ•œ ๋ฒˆ์— ์ •๋ฆฌํ•˜๊ธด ์–‘์ด ๋„ˆ๋ฌด ๋ฐฉ๋Œ€ํ•˜์—ฌ ์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ๊ธฐ์กด Vue.js์™€ ๋น„๊ตํ•˜์—ฌ ์•Œ์•„๋‘๋ฉด ์ข‹์„ ์  ๊ทธ๋ฆฌ๊ณ  ์‹ ๊ทœ ๋ฌธ์„œ์—์„œ ๊ผญ ํ•œ ๋ฒˆ์”ฉ ์‚ดํŽด๋ณด๋ฉด ์ข‹์„ ๋งŒํ•œ ๋‚ด์šฉ ๋“ฑ์„ ์ „๋‹ฌํ•˜๋ ค ํ•ฉ๋‹ˆ๋‹ค.

์˜ค๋Š˜ ๊ฐ„๋‹จํžˆ Vue 3์— ๋Œ€ํ•ด์„œ ๋“ฑ์žฅ ๋ฐฐ๊ฒฝ๊ณผ ์†Œ๊ฐœ ์ •๋„๋ฅผ ์•Œ์•„๋ณด๊ณ  ๋‹ค์Œ์— ์—ฐ์žฌ๋  2๊ฐ€์ง€ ์‹œ๋ฆฌ์ฆˆ์—์„œ ์ข€ ๋” ๊นŠ์ˆ™ํ•˜๊ฒŒ Vue 3๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค ๐Ÿ˜„

  • Vue 3 ์ปดํฌ์ง€์…˜ API(์—ฐ์žฌ ์˜ˆ์ • ์ค‘)
  • Vue 3 ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๊ฐ€์ด๋“œ(์—ฐ์žฌ ์˜ˆ์ • ์ค‘)

Vue 3์˜ ์ถœ์‹œ ์˜ˆ์ •์ผ? ํ˜„์žฌ ๋‹จ๊ณ„๋Š”?

์ƒˆ๋กœ์šด ๋ทฐ ๋ฒ„์ „์ด ๊ณง ๋“ฑ์žฅํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ ๋ฒ ํƒ€(Beta) ๋ฒ„์ „์„ ์ง€๋‚˜ ๋ฆด๋ฆฌ์ฆˆ ํ›„๋ณด(Release Candidate) ๋‹จ๊ณ„์— ์žˆ์Šต๋‹ˆ๋‹ค. ์ข€ ๋” ์‰ฝ๊ฒŒ ์–˜๊ธฐํ•˜๋ฉด ๊ณง ๊ณต์‹ ๋ฒ„์ „์œผ๋กœ ์ถœ์‹œ๋˜๊ธฐ ์ง์ „์ด๋ผ๋Š” ๋ง์ด์ฃ  ๐Ÿ˜„

์ €ํฌ๊ฐ€ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ๋ทฐ ์ฝ”์–ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ฃผ๋ณ€ ์ƒํƒœ๊ณ„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(๋ทฐ์—‘์Šค, ๋ทฐ ๋ผ์šฐํ„ฐ)๋„ ๋ฒ ํƒ€ ๋‹จ๊ณ„์ด๊ธฐ ๋•Œ๋ฌธ์— ์•„๋งˆ ์˜ฌํ•ด๊ฐ€ ๊ฐ€๊ธฐ ์ „์—๋Š” ๊ณต์‹ ๋ฒ„์ „์œผ๋กœ ์ถœ์‹œ๋  ํ™•๋ฅ ์ด ๋งค์šฐ ๋†’์•„์กŒ์Šต๋‹ˆ๋‹ค.

๐Ÿ“ข Vue.js 3 One Piece๊ฐ€ ์ถœ์‹œ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค - 9์›” 19์ผ

Vue 3์ด๋ผ๋‹ˆ.. ์—ฌํƒœ๊นŒ์ง€ ๋ฐฐ์šด๊ฒŒ ๋‹ค ์†Œ์šฉ ์—†๋Š”๊ฑด๊ฐ€์š”?

ํŽ˜์ด์ง€ ์Šคํฌ๋กค์„ ๋” ๋‚ด๋ฆฌ๊ธฐ ์ „์— ํ•œ๊ฐ€์ง€ ์งš๊ณ  ๋„˜์–ด๊ฐˆ ๋ถ€๋ถ„์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋งˆ ์ƒˆ๋กœ์šด Vue.js ๋ฒ„์ „์„ ๋งˆ์ฃผํ•˜๋ฉด์„œ ์•„๋ž˜์™€ ๊ฐ™์€ ์ƒ๊ฐ์ด ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

โ€œ์ „ ์ด์ œ ๊ฒจ์šฐ ๋ทฐ์— ์ž…๋ฌธํ–ˆ๋Š”๋ฐ ์‹ ๊ทœ ๋ฒ„์ „์ด๋ผ๋‹ˆ ๋‹ค์‹œ ๋ฐฐ์›Œ์•ผ ํ•˜๋Š”๊ฑฐ ์•„๋‹Œ๊ฐ€์š”?โ€
โ€œ์ƒˆ ํ”„๋กœ์ ํŠธ ์‹œ์ž‘ํ•˜๋Š”๋ฐ ๊ทธ๋Ÿผ ๋ทฐ 3์ด ๋‚˜์˜ฌ ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ธ๋‹ค๊ฐ€ ํ•ด์•ผ ํ•˜๋‚˜์š”?โ€

์‹ค์ œ๋กœ ๋ช‡ ์ผ ์ „์— ์œ„์™€ ์œ ์‚ฌํ•œ ์งˆ๋ฌธ์„ ๋ฐ›๊ธฐ๋„ ํ–ˆ๋Š”๋ฐ์š”. ์—ฌ๊ธฐ์„œ ๋ง์”€๋“œ๋ฆฌ๊ณ  ์‹ถ์€ ์ ์€ ํ•œ ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค.

โ€œVue 3์€ ๊ธฐ์กด Vue 2์™€ ๋น„๊ตํ•ด์„œ ์ „์ฒด์ ์ธ ์ปจ์…‰๊ณผ ๊ฐœ๋…์ด ํฌ๊ฒŒ ๋‹ฌ๋ผ์ง€์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. Composition API ๋ผ๋Š” ์ธ์Šคํ„ด์Šค ์˜ต์…˜ ์†์„ฑ์ด ์ƒˆ๋กœ ์ถ”๊ฐ€ ๋˜์—ˆ๊ธฐ๋Š” ํ•˜์ง€๋งŒ ์ด ์†์„ฑ์„ ์“ฐ์ง€ ์•Š๊ณ ๋„ ์ง€๊ธˆ๊นŒ์ง€ ๋ฐฐ์›Œ์˜จ ๋‚ด์šฉ๋“ค๋กœ ์ถฉ๋ถ„ํžˆ ๋ชจ๋˜ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค ๐Ÿ˜„โ€

์‹ ๊ทœ ๋ฒ„์ „์ด ์˜ค๋žœ ๊ธฐ๊ฐ„ ๋™์•ˆ ์ค€๋น„๋˜์–ด ์˜จ ๋งŒํผ ์ €๋„ ๊ด€๋ จ ์ž๋ฃŒ๋“ค์„ ํ™•์ธํ•˜๊ณ  ์„œ๋น„์Šค๋ฅผ ๋งŒ๋“ค์–ด๋ณด๋ฉด์„œ Composition API์— ๋Œ€ํ•œ ๋ช‡ ๊ฐ€์ง€ ๊ด€์ ์ด ์ƒ๊ฒผ๋Š”๋ฐ์š”. ์ถ”ํ›„์— ๋ณ„๋„๋กœ ์–˜๊ธฐ๋ฅผ ํ•ด๋ณด๋ ค ํ•ฉ๋‹ˆ๋‹ค ๐Ÿ˜„

Vue 3์—์„œ ํ•ด๊ฒฐํ•˜๋ ค๋Š” ๋ฌธ์ œ์ 

๋ทฐ 3์€ ์ž‘๋…„ 6์›”๊ฒฝ๋ถ€ํ„ฐ ๊ฝค ์˜ค๋žœ ์‹œ๊ฐ„ ๋™์•ˆ ์ปค๋ฎค๋‹ˆํ‹ฐ์— ๋ฐฉํ–ฅ์„ฑ์„ ๊ณต์œ ํ•˜๋ฉด์„œ ๋‹ค๋“ฌ์–ด ์™”์Šต๋‹ˆ๋‹ค.

vue3-rfc-comments

์ฒ˜์Œ์—๋Š” ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ข€ ๋” ๋งค๋„๋Ÿฝ๊ฒŒ ํฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ํด๋ž˜์Šค(ES6 Class) ๊ธฐ๋ฐ˜ ์ปดํฌ๋„ŒํŠธ ์ฝ”๋“œ ์ž‘์„ฑ ๋ฐฉ์‹์„ ๊ณ ๋ฏผํ•˜๋‹ค๊ฐ€ ์ตœ์ข…์ ์œผ๋กœ ํ˜„์žฌ์˜ ๊ฐ์ฒด ์Šคํƒ€์ผ ์ปดํฌ๋„ŒํŠธ ์˜ต์…˜ ์†์„ฑ ์ •์˜ ๋ฐฉ์‹์„ ์ฑ„ํƒํ–ˆ์ฃ .

๋ทฐ 3์ด ์ถ”๊ตฌํ•˜๋Š” ๋ฐฉํ–ฅ์€ ํฌ๊ฒŒ 2๊ฐ€์ง€๋กœ ์š”์•ฝํ•ด ๋ณผ ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ์ปดํฌ๋„ŒํŠธ ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ ํ–ฅ์ƒ
  • ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ๋ฌธ๋ฒ• ์ง€์›

๊ธฐ์กด ๋ทฐ ๋ฒ„์ „์—์„œ ํ•œ๊ณ„์ ์œผ๋กœ ์–ธ๊ธ‰๋˜๋˜ ์ด 2๊ฐ€์ง€๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋ทฐ 3์ด ๋“ฑ์žฅํ–ˆ์Šต๋‹ˆ๋‹ค.

Vue.js์˜ ๊ธฐ์กด ํ•œ๊ณ„์  - ์ปดํฌ๋„ŒํŠธ ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ

๋ชจ๋˜ ํ”„๋ŸฐํŠธ์—”๋“œ ํ”„๋ ˆ์ž„์›Œํฌ๋“ค์€ ๋ชจ๋‘ ์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ฐ˜ UI ๊ฐœ๋ฐœ ๋ฐฉ์‹์„ ์ถ”๊ตฌํ•ฉ๋‹ˆ๋‹ค. ์ฝ”๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ํŽธํ•˜๊ฒŒ ๋งŒ๋“ค๋ฉด์„œ ์ถ”ํ›„์— ๋””๋ฒ„๊น…๋„ ์ˆ˜์›”ํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด์ฃ . ๋ทฐ๋Š” ์ปดํฌ๋„ŒํŠธ ์ฝ”๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋Œ€ํ‘œ์ ์œผ๋กœ ์•„๋ž˜ 3๊ฐ€์ง€ ๋ฐฉ์‹์„ ์ถ”์ฒœํ•˜๊ณ  ์žˆ๋Š”๋ฐ์š”.

  • ์Šฌ๋กฏ(Slots & Scoped Slots)
  • ๋ฏน์Šค์ธ(Mixins)
  • ํ•˜์ด ์˜ค๋” ์ปดํฌ๋„ŒํŠธ(High Order Components)

์—ฌ๊ธฐ์„œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์— ๋ฐ€์ ‘ํ•˜๊ฒŒ ์—ฐ๊ด€๋œ ๋กœ์ง๋“ค์„ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ณดํ†ต ๋ฏน์Šค์ธ์„ ๋งŽ์ด ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. (๊ฐœ์ธ์ ์ธ ์ƒ๊ฐ์ด์ง€๋งŒ ํ•˜์ด ์˜ค๋” ์ปดํฌ๋„ŒํŠธ๋ณด๋‹ค ๋ฏน์Šค์ธ์ด ๋Œ€๋‹ค์ˆ˜ ๊ฐœ๋ฐœ์ž๋“ค์—๊ฒŒ ์„ ํ˜ธ๋˜๋Š” ์ด์œ ๋Š” ๊ฐœ๋…๊ณผ ๋ฌธ๋ฒ•์ด ๋” ์‰ฝ๊ธฐ ๋•Œ๋ฌธ์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค)

๋ฏน์Šค์ธ์€ ์ปจ๋ฒค์…˜์ด ๊ต‰์žฅํžˆ ์ค‘์š”ํ•œ ๋ฌธ๋ฒ•์ธ๋ฐ์š”. ๋ฏน์Šค์ธ์— data, methods์™€ ๊ฐ™์€ ์†์„ฑ์„ ์ •์˜ํ•  ๋•Œ๋Š” ๋ฏน์Šค์ธ์„ ์ฃผ์ž…ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ์˜ ์˜ต์…˜ ์†์„ฑ๊ณผ ๋ฏน์Šค์ธ ์†์„ฑ์„ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•ด ์ ‘๋‘์‚ฌ๋ฅผ ๋ถ™์ด๊ฑฐ๋‚˜ ํŒ€ ๋‚ด ์ปจ๋ฒค์…˜์„ ์—„๊ฒฉํ•˜๊ฒŒ ์ •์˜ํ•˜๋Š” ๊ฒŒ ์ข‹์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ์ƒํ™ฉ์—์„œ ๊ฝค ๊ณจ๋จธ๋ฆฌ๋ฅผ ์ฉํž™๋‹ˆ๋‹ค.

<!-- App.vue -->
<template>
  <main>
    <h1>์˜ค๋Š˜์˜ ๋‚ ์งœ {{ currentDate }}</h1>
    <todo-item v-for="item in items" :item="item" :id="formatId(item.id)"></todo-item>
  </main>
</template>

<script>
import ItemMixins from './mixins/ItemMixins.js'
import TodoMixins from './mixins/TodoMixins.js'
import MyMixins from './mixins/MyMixins.js'

export default {
  mixins: [ItemMixins, TodoMixins, MyMixins]
  data() {
    return {
      todoItems: ['์ด ๋ฐ์ดํ„ฐ ์†์„ฑ์€', '์“ฐ์ผ ๊นŒ์š”?', '์•ˆ ์“ฐ์ผ๊นŒ์š”?]
    }
  },
  methods: {
    formatCurrentDate(value) {
      // ...
      this.currentDate = this.formatDate(value);
    }
  },
  // ...
}
</script>

๋ฏน์Šค์ธ์€ ํŠน์ • ์ปดํฌ๋„ŒํŠธ์— 2๊ฐœ ์ด์ƒ ์‚ฌ์šฉํ•˜๋Š” ์ˆœ๊ฐ„ ๋กœ์ง์˜ ํ๋ฆ„์„ ๋”ฐ๋ผ๊ฐ€๊ธฐ๊ฐ€ ์–ด๋ ต๊ณ , ์‹ค์ œ ํ•ด๋‹น data๋‚˜ methods๊ฐ€ ์–ด๋А ๋ฏน์Šค์ธ์— ์ •์˜๋˜์–ด ์žˆ๋Š”์ง€ ํŒŒ์•…ํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ๋ฏน์Šค์ธ์€ ์—„๊ฒฉํ•œ ๊ทœ์น™์œผ๋กœ ์‚ฌ์šฉ ๋ฒ”์œ„์™€ ๋ณ€์ˆ˜ ๋ช…์„ ์ œํ•œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Vue.js์˜ ๊ธฐ์กด ํ•œ๊ณ„์  - ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ง€์›

๋ทฐ๋Š” ์ž…๋ฌธ์ž๋“ค์ด ์‰ฝ๊ฒŒ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ๋ฐฐ์šธ ์ˆ˜ ์žˆ๋„๋ก ํด๋ž˜์Šค ๊ธฐ๋ฐ˜์˜ ์ปดํฌ๋„ŒํŠธ ์ฝ”๋“œ ์ •์˜ ๋ฐฉ์‹์ด ์•„๋‹Œ ๊ฐ์ฒด ์Šคํƒ€์ผ์˜ ์ปดํฌ๋„ŒํŠธ ์ฝ”๋“œ ์ •์˜ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ฐ๊ฐ์˜ ์ฝ”๋“œ ์Šคํƒ€์ผ์ด ์–ด๋–ป๊ฒŒ ๋‹ค๋ฅธ์ง€ ํ•œ๋ฒˆ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

// ํด๋ž˜์Šค ๊ธฐ๋ฐ˜ ์ปดํฌ๋„ŒํŠธ ์ฝ”๋“œ ์ž‘์„ฑ ๋ฐฉ์‹
class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      num: 10
    }
  }
  
  render() {
    return (
      <div>
        <h1>Hello, {this.props.name}</h1>
        <p>{ num }</p>
      </div>
    )
  }
}
// ๊ฐ์ฒด ๊ธฐ๋ฐ˜ ์ปดํฌ๋„ŒํŠธ ์ฝ”๋“œ ์ž‘์„ฑ ๋ฐฉ์‹
new Vue({
  props: ['name'],
  data: {
    num: 10,
  },
  template: `
    <div>
      <h1>Hello, {{ name }}</h1>
      <p>{{ num }}</p>
    </div>
  `
})

์œ„์™€ ๊ฐ™์ด ๊ฐ์ฒด ๊ธฐ๋ฐ˜ ์ฝ”๋“œ ์ž‘์„ฑ ๋ฐฉ์‹์€ ์ตœ์‹  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋ฌธ๋ฒ•์— ์ต์ˆ™ํ•˜์ง€ ์•Š์€ ์ž…๋ฌธ์ž๋‚˜ ์˜ˆ์ „ ์›น ๊ฐœ๋ฐœ ๋ฐฉ์‹์— ์ต์ˆ™ํ•œ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ํ•™์Šต ๋ถ€๋‹ด๊ฐ์„ ๋œ์–ด์ฃผ๊ณ  ์ฝ”๋“œ ๊ฐ€๋…์„ฑ์„ ๋†’์—ฌ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์• ์‹œ๋‹น์ดˆ ์ง„์ž… ์žฅ๋ฒฝ์„ ๋‚ฎ์ถ”๊ธฐ ์œ„ํ•ด ๊ฐ์ฒด ์Šคํƒ€์ผ์„ ์‚ฌ์šฉํ•˜๋‹ค ๋ณด๋‹ˆ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ง€์›ํ•˜๊ธฐ์—๋Š” ์ข€ ๋ฒ„๊ฑฐ์šด ๊ตฌ์กฐ๋ฅผ ๊ฐ–๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์˜ ํƒ€์ž… ์ถ”๋ก  ๋ฐฉ์‹์€ ๊ฐ์ฒด ๊ตฌ์กฐ๋ณด๋‹ค ํ•จ์ˆ˜ ๊ตฌ์กฐ์—์„œ ๋” ์ด์ ์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๊ธฐ์กด ๋ทฐ ๋ฒ„์ „์—์„œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ํด๋ž˜์Šค ๋ฌธ๋ฒ•๋“ค๋กœ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ๊ฐœ๋ฐœํ•˜๊ธฐ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

<!-- MyButton.vue -->
<template>
  <button @click="sayHi">say hi</button>
</template>

<script lang="ts">
import Vue from 'vue';
import Component from 'vue-class-component';

// ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์ด์šฉํ•œ ์ปดํฌ๋„ŒํŠธ ์ •์˜
@Component
export default class App extends Vue {
  // data ์†์„ฑ
  message = 'hello';

  // methods ์†์„ฑ
  sayHi() {
    console.log(this.message);
  }
}
</script>

์—ฌ๋‹ด์œผ๋กœ ์•ต๊ทค๋Ÿฌ๋ฅผ ์˜ค๋ž˜ ์‚ฌ์šฉํ•˜์‹  ์ง€์ธ ๋ถ„๊ป˜ ์ด๊ฑฐ ์•ต๊ทค๋Ÿฌ ์•„๋‹ˆ๋ƒ ๋ผ๋Š” ์†Œ๋ฆฌ๋ฅผ ๋“ค์€ ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค๋งŒ.. ์‚ฌ์‹ค ์ €๋„ ๋ฐ˜๋ฐ•ํ•˜๊ธฐ ์–ด๋ ค์šด ๊ตฌ์กฐ์˜€์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ, ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๊ผญ ์œ„์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ๊ฐœ๋ฐœํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์™€ ๊ฐ™์€ ๊ตฌ์กฐ๋กœ๋„ ์ถฉ๋ถ„ํžˆ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์˜ ๊ธฐ๋Šฅ์„ ์ง€์›๋ฐ›์œผ๋ฉฐ ์„œ๋น„์Šค๋ฅผ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค ๐Ÿ˜„

<template>
  <button @click="sayHi">say hi</button>
</template>

<script lang="ts">
import Vue from 'vue';

export default Vue.extend({
  data() {
    return { message: 'hello' }
  },
  methods: {
    sayHi() {
      console.log(this.message);
    }
  }
});
</script>

ํ•˜์ง€๋งŒ ์—ฌ์ „ํžˆ ์ฃผ๋ณ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ํƒ€์ž… ์ง€์›์ด ๋ถ€์‹คํ•œ ๊ฑด ์‚ฌ์‹ค์ž…๋‹ˆ๋‹ค. ์•„๋ž˜์™€ ๊ฐ™์€ ์ƒํ™ฉ์—์„œ๋Š” ๋งค๋ฒˆ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ผ์ผ์ด ํƒ€์ž…์„ ์ •์˜ํ•ด ์ค˜์•ผ ํ•˜์ฃ .

// routes.ts
new VueRouter({
  routes: [
    {
      path: '/',
      component: MainView
      beforeEnter(to: object, from: object, next: Function) {
        // to์™€ from์— ๋Œ€ํ•œ ํƒ€์ž…์„ ์‰ฝ๊ฒŒ ์ž„ํฌํŠธ ํ•  ์ˆ˜ ์—†์–ด ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ํƒ€์ž…์„ ์ •์˜ํ•ด์ค˜์•ผ ํ•จ
      }
    }
  ]
})

Vue 3์—์„œ๋Š” ๋ฌด์—‡์ด ๋‹ฌ๋ผ์กŒ๋Š”๊ฐ€?

๊ทธ๋ž˜์„œ ์•ž์—์„œ ์‚ดํŽด๋ณธ ํ•œ๊ณ„์ ๋„ ๋ณด์™„ํ•˜๊ณ  ์‚ฌ์šฉ์ž๊ฐ€ ๋” ๋‹ค์–‘ํ•œ ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ฐ”๋€Œ์—ˆ์Šต๋‹ˆ๋‹ค. ํฌ๊ฒŒ ์š”์•ฝํ•˜๋ฉด ์•„๋ž˜ 5๊ฐ€์ง€์ž…๋‹ˆ๋‹ค.

  • Teleport(Vue Portal๊ณผ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค)
  • ํ…œํ”Œ๋ฆฟ ํ‘œํ˜„์‹ ๊ด€๋ จ ์ถ”๊ฐ€ ๋ฌธ๋ฒ• ์ œ๊ณต
  • Suspense
  • Reactivity ์ฃผ์ž… API
  • ๊ทธ๋ฆฌ๊ณ  Composition API

๊ฐ๊ฐ์˜ ํŠน์ง•์€ ์ถ”ํ›„ ๋ณ„๋„์˜ ํฌ์ŠคํŒ…์—์„œ ์ž์„ธํžˆ ๋‹ค๋ค„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์˜ค๋Š˜ ํ•œ ๋ฒˆ์— ๋‹ค ๋ฐฐ์šฐ๊ธฐ์—๋Š” ์–‘์ด ๋„ˆ๋ฌด ๋งŽ๊ณ  ๋จธ๋ฆฌ๊ฐ€ ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ์œผ๋‹ˆ๊นŒ์š” ๐Ÿ˜„

์˜ค๋Š˜์€ ๊ธฐ์กด ๋ฌธ๋ฒ•์—์„œ ์ถ”๊ฐ€๋œ ๋‚ด์šฉ๋“ค๋งŒ ์‚ดํŽด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค ๐Ÿ˜„

Teleport์™€ ๋ทฐ ํฌํƒˆ ์‚ฌ์šฉ๋ฒ•์€ ๊ฑฐ์˜ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๊ฐœ๋…์ ์ธ ์ฐจ์ด๊ฐ€ ์žˆ๋Š”๋ฐ ๊ทธ๊ฑด ์ถ”ํ›„ ๋ณ„๋„ ํฌ์ŠคํŒ…์œผ๋กœ ๋‹ค๋ฃจ๊ฒ ์Šต๋‹ˆ๋‹ค ๐Ÿ˜„

Vue 3 ๊ณต์‹ ๋ฌธ์„œ์— ๋Œ€ํ•œ ์ฒซ ์ธ์ƒ

์ผ๋‹จ ์ƒˆ ๊ณต์‹ ๋ฌธ์„œ์— ๋Œ€ํ•œ ์–˜๊ธฐ๋ฅผ ์ž ๊น ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜ 2๊ฐ€์ง€๊ฐ€ ํฌ๊ฒŒ ๋‹ฌ๋ผ์กŒ๋„ค์š”.

  • ๋ทฐ ํ”„๋ ˆ์Šค(VuePress)๊ธฐ๋ฐ˜ ์‚ฌ์ดํŠธ ์ œ์ž‘
  • ๋ฌธ์„œํ™” ๋‹ด๋‹น์ž ๋ณ€๊ฒฝ

Vue 3 ๊ณต์‹ ๋ฌธ์„œ๋Š” ์ด์ „ ๋ฒ„์ „๊ณผ ๋‹ค๋ฅด๊ฒŒ ๋ทฐ ํ”„๋ ˆ์Šค๋ผ๋Š” Vue.js ๊ธฐ๋ฐ˜ ๋ฌธ์„œํ™” ๋„๊ตฌ๋ฅผ ์ด์šฉํ•˜์—ฌ ์ œ์ž‘๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ํŠน์ • ์ฝ”๋“œ ๋ผ์ธ์„ ๊ฐ•์กฐํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‚˜ ์•ฑ์„ ์„ค์น˜ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ(Progressive Web Apps)์ด ์ถ”๊ฐ€๋กœ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค.

๋ฌธ์„œํ™” ๋‹ด๋‹น์ž๋„ ๋ฏธ๊ตญ ์ปจ์„คํ„ดํŠธ์ด์ž ๊ธฐ์กด ๋‹ด๋‹น์ž์ธ ํฌ๋ฆฌ์Šค(Chris)๊ฐ€ ์•„๋‹ˆ๋ผ ๋””์ž์ธ ํŠนํ™” ํ”„๋ŸฐํŠธ ๊ฐœ๋ฐœ์ž์ธ ์‚ฌ๋ผ(Sarah Drasner)๊ฐ€ ์ฃผ๋„ํ•œ ๊ฒƒ์œผ๋กœ ๋ณด์ด๋„ค์š”. ์‚ฌ๋ผ๋Š” ํ”„๋ŸฐํŠธ์—”๋“œ ๊ฐœ๋ฐœ ์ชฝ์—์„œ ๊ฝค ์ธ์ง€๋„๊ฐ€ ๋†’์€ CSS Trick์˜ ๊ธฐ๊ณ ์ž์ด์ž ์œ ๋ช…ํ•œ ์ฝ”๋“œ ํ•˜์ด๋ผ์ดํŒ… ๋„๊ตฌ์ธ Night Owl์„ ๋งŒ๋“  ์‚ฌ๋žŒ์ž…๋‹ˆ๋‹ค. ํ˜„์žฌ ๋ทฐ ์ฝ”์–ด ํŒ€์œผ๋กœ ํ™œ๋™ํ•˜๊ณ  ์žˆ์ฃ .

Vue 3 ํ›‘์–ด๋ณด๊ธฐ - ๊ธฐ๋ณธ ๋ฌธ๋ฒ• ํŽธ

์ž ๊ทธ๋Ÿผ ๋ณธ๊ฒฉ์ ์œผ๋กœ ๋ทฐ 3 ๊ณต์‹ ๋ฌธ์„œ์˜ ์ฃผ์š” ํฌ์ธํŠธ๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ธฐ์กด Vue.js ์ง€์‹์—์„œ ํฌ๊ฒŒ ๋ฒ—์–ด๋‚˜์ง€ ์•Š๋Š” ์„ ์œผ๋กœ ๊ธฐ๋ณธ ๋ฌธ๋ฒ•๋“ค์„ ์ •๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค. ํฌ๊ฒŒ ์•„๋ž˜ 2๊ฐ€์ง€ ๊ด€์ ์—์„œ ์ •๋ฆฌํ–ˆ์œผ๋‹ˆ ์ฐธ๊ณ ํ•ด ์ฃผ์„ธ์š” ๐Ÿ˜„

๐Ÿ’ก ์•„๋ž˜ ๋‚ด์šฉ์€ Vue 3 ๊ณต์‹ ๋ฌธ์„œ์˜ Essential ๋ฉ”๋‰ด์™€ Component in-Depth ๋ฉ”๋‰ด๋ฅผ ๋ณด๊ณ  ์ •๋ฆฌํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

Vue 3์—์„œ ์ƒˆ๋กญ๊ฒŒ ์ถ”๊ฐ€๋˜๊ฑฐ๋‚˜ ๊ผญ ํ™•์ธํ•ด์•ผ ํ•  ๋ฌธ๋ฒ•๋“ค

1. ๋””๋ ‰ํ‹ฐ๋ธŒ ๋ฌธ๋ฒ•์˜ ์ธ์ž(Arguments)

๋ทฐ 3์—์„œ ๋™์  ์ธ์ž(Dynamic Arguments)๋ผ๋Š” ๊ฐœ๋…์ด ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋””๋ ‰ํ‹ฐ๋ธŒ์˜ ๋Œ€์ƒ(arguments)์ด ๋ทฐ ์ธ์Šคํ„ด์Šค ๋ฐ์ดํ„ฐ์™€ ์—ฐ๊ฒฐ๋  ์ˆ˜ ์žˆ๊ฒŒ ๋ฌธ๋ฒ•์ด ์ง€์›๋ฉ๋‹ˆ๋‹ค. v-on: ๋””๋ ‰ํ‹ฐ๋ธŒ๋‚˜ v-bind:๋””๋ ‰ํ‹ฐ๋ธŒ์˜ ๋Œ€์ƒ์„ ์•„๋ž˜์™€ ๊ฐ™์ด ๋ทฐ ๋ฐ์ดํ„ฐ ์†์„ฑ์œผ๋กœ ์—ฐ๊ฒฐํ•˜์—ฌ ์„ ์–ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

<!-- ๋ฌธ๋ฒ• ์˜ˆ์‹œ -->
<a v-bind:[attributeName]="url">...</a>

์œ„์˜ ์˜ˆ์‹œ ๋ฌธ๋ฒ•์— ์‹ค์ œ ์ฝ”๋“œ๋ฅผ ์ ์šฉํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ๋ชจ์Šต์ž…๋‹ˆ๋‹ค.

<a v-bind:[linkAttribute]="url">...</a>
data() {
  return {
    linkAttribute: 'href' // ์œ„ `myAttribute`๊ฐ€ `href`๋กœ ์„ ์–ธ๋จ
  }
}

2. ์ถ•์•ฝ ๋ฌธ๋ฒ•

๋””๋ ‰ํ‹ฐ๋ธŒ์— ๋™์  ์ธ์ž๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์•„๋ž˜์™€ ๊ฐ™์€ ์ถ•์•ฝ ๋ฌธ๋ฒ•๋„ ์ง€์›๋ฉ๋‹ˆ๋‹ค.

<!-- ๊ธฐ๋ณธ ๋ฌธ๋ฒ• -->
<a v-bind:href="imageUrl">
<a v-on:click="logText">
<a v-bind:[myAttribute]="imageUrl"> <!-- ์ถ”๊ฐ€๋œ ๋ฌธ๋ฒ• -->
<!-- ์ถ•์•ฝ ๋ฌธ๋ฒ• -->
<a :href="imageUrl">
<a @click="logText">
<a :[myAttribute]="imageUrl"> <!-- ์ถ”๊ฐ€๋œ ๋ฌธ๋ฒ•(์ถ•์•ฝํ˜•) -->

3. ๋ฉ€ํ‹ฐ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ

์ผ๋ฐ˜์ ์œผ๋กœ ๊ธฐ์กด ๋ทฐ ๋ฌธ๋ฒ•์—์„œ DOM ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ํ•˜๋‚˜๋งŒ ๋ถ€์ฐฉํ•ด์„œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

<!-- ์˜ˆ์‹œ -->
<button @click="logText">log</button>
methods: {
  logText(event) {
    if (event) {
      event.preventDefault();
    }
  }
}

์ด์ œ๋Š” ํ…œํ”Œ๋ฆฟ ํ‘œํ˜„์‹์—์„œ ํŠน์ • DOM์˜ ์ด๋ฒคํŠธ๋ฅผ ์—ฌ๋Ÿฌ ๋ฉ”์„œ๋“œ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ๋ฒ•์ด ์ง€์›๋ฉ๋‹ˆ๋‹ค.

<!-- ์˜ˆ์‹œ -->
<button @click="logText($event), sayHi($event)">log</button>
methods: {
  logText(event) {
    // ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๊ด€๋ จ ์ฒซ ๋ฒˆ์งธ ๋กœ์ง
  },
  sayHi(event) {
    // ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๊ด€๋ จ ๋‘ ๋ฒˆ์งธ ๋กœ์ง
  }
}

4. ํ‚ค๋ณด๋“œ ์ด๋ฒคํŠธ ์ œ์–ด ๋ฌธ๋ฒ• ์ถ”๊ฐ€

๊ธฐ์กด ๋ฌธ๋ฒ•์—์„œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ํŠน์ • ํ‚ค์˜ ์ž…๋ ฅ์„ ์ œ์–ดํ–ˆ์Šต๋‹ˆ๋‹ค.

<input @keyup.enter="addTodo">

enterํ‚ค ์ด์™ธ์—๋„ ์•„๋ž˜ ํ‚ค ๋ชฉ๋ก์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

# Key Modifier
.enter
.tab
.delete
.esc
.space
.up
.down
.left
.right

์ด์ œ๋Š” ๊ณต์‹ ๋ฌธ์„œ์—์„œ ์•ˆ๋‚ด๋˜์ง€ ์•Š๋Š” ํ‚ค ์ž…๋ ฅ์— ๋Œ€ํ•ด์„œ๋„ ์•„๋ž˜์™€ ๊ฐ™์€ ๊ทœ์น™์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

<!-- "KeyboardEvent.key" ๊ฐ’์ด PageDown์ธ ๊ฒฝ์šฐ ์•„๋ž˜์™€ ๊ฐ™์ด ์ผ€๋ฐฅ์œผ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๋ถ™์ผ ์ˆ˜ ์žˆ์Œ -->
<input @keyup.page-down="onPageDown" />

5. ์ปดํฌ๋„ŒํŠธ ํ†ต์‹  ๋ฐฉ๋ฒ• - ์ด๋ฒคํŠธ ์—๋ฐ‹ ์ธ์ž ์ „๋‹ฌ

์ปดํฌ๋„ŒํŠธ ํ†ต์‹  ๋ฐฉ๋ฒ• ์ค‘ ์ด๋ฒคํŠธ ์—๋ฐ‹(event emit)์— ๋Œ€ํ•œ ์ถ”๊ฐ€์ ์ธ ๋ฌธ๋ฒ•์ด ์ง€์›๋ฉ๋‹ˆ๋‹ค. ์•„๋ž˜์™€ ๊ฐ™์€ ์ปดํฌ๋„ŒํŠธ ๊ตฌ์กฐ๊ฐ€ ์žˆ์„ ๋•Œ

App
โ””โ”€TodoList
  โ””โ”€TodoItem

TodoItem ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ฐœ์ƒํ•œ ์ด๋ฒคํŠธ์˜ ์ธ์ž๋ฅผ ๋ฃจํŠธ ์ปดํฌ๋„ŒํŠธ์ธ App์— ์ „๋‹ฌ ๋ฐ›์œผ๋ ค๋ฉด ์ค‘๊ฐ„์— ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ์ธ TodoList ์ปดํฌ๋„ŒํŠธ์—์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ์ด๋ฒคํŠธ๋ฅผ ์ค‘๊ฐœํ•ด์ค˜์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

<!-- TodoItem.vue -->
<template>
  <li>
    <button @click="$emit('remove', 10)">remove</button>
  </li>
</template>

<!-- TodoList.vue -->
<template>
  <ul>
    <todo-item @remove="removeItem"></todo-item>
  </ul>
</template>

<script>
export default {
  methods: {
    removeItem(num) {
      this.$emit('remove', num);
    }
  }
}
</script>

<!-- App.vue -->
<template>
  <div>
    <todo-list @remove="removeTodo"></todo-list>
  </div>
</template>

<script>
export default {
  methods: {
    removeTodo(num) {
      axios.delete('/todo/' + num);
    }
  }
}
</script>

ํ•˜์ง€๋งŒ ์ด์ œ๋Š” ์œ„์™€ ๊ฐ™์ด ์ด๋ฒคํŠธ๋ฅผ ์ค‘๊ฐœํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ž‘์„ฑํ•  ํ•„์š” ์—†์ด ํ…œํ”Œ๋ฆฟ ํ‘œํ˜„์‹์—์„œ ์ด๋ฒคํŠธ๋ฅผ ์ธ์ž์™€ ํ•จ๊ป˜ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์— ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

<!-- TodoItem.vue -->
<template>
  <li>
    <button @click="$emit('remove', 10)">remove</button>
  </li>
</template>


<!-- TodoList.vue -->
<template>
  <ul>
    <todo-item @remove="$emit('remove', $event)"></todo-item>
  </ul>
</template>

<!-- App.vue -->
<template>
  <div>
    <todo-list @remove="removeTodo"></todo-list>
  </div>
</template>

<script>
export default {
  methods: {
    removeTodo(num) {
      axios.delete('/todo/' + num);
    }
  }
}
</script>

๐Ÿ’ฌ ์‚ฌ์‹ค ์œ„ ๋ฌธ๋ฒ•์€ ๊ธฐ์กด Vue.js ๋ฒ„์ „์—์„œ๋„ ๋™์ผํ•˜๊ฒŒ ๋™์ž‘ํ•˜๋Š” ๋ถ€๋ถ„์ธ๋ฐ ๋ฏธ์ฒ˜ ๋ชฐ๋ž๋˜ ๋ถ€๋ถ„์ด์—ˆ๋„ค์š” ๐Ÿ˜„

6. ํ”„๋กญ์Šค ์†์„ฑ

ํ”„๋กญ์Šค ์†์„ฑ์— ์ผ๋ฐ˜ ๋ฌธ์ž์—ด์„ ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒƒ๊ณผ ๋ทฐ ์ธ์Šคํ„ด์Šค์˜ data๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒƒ์˜ ์ฐจ์ด์ ์„ ๋ณด์—ฌ์ฃผ๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

<!-- ํ”„๋กญ์Šค ์†์„ฑ์— ์ผ๋ฐ˜ ๋ฌธ์ž์—ด์„ ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒฝ์šฐ -->
<template>
  <app-header title="News Tonight"></app-header>
</template>
<!-- ํ”„๋กญ์Šค ์†์„ฑ์— ๋ทฐ ๋ฐ์ดํ„ฐ๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒฝ์šฐ -->
<template>
  <app-header :title="appTitle"></app-header>
</template>

<script>
export default {
  data() {
    return {
      appTitle: 'News Tonight'
    }
  }
}
</script>

์—ฌ๊ธฐ์„œ ์ƒˆ๋กœ์šด ๋ฌธ๋ฒ•์„ ํ•˜๋‚˜ ๋” ์–ธ๊ธ‰ํ•˜๊ณ  ์žˆ๋Š”๋ฐ ํ”„๋กญ์Šค ์†์„ฑ์— ๊ฐ’์„ ์—ฐ๊ฒฐํ•˜์ง€ ์•Š์œผ๋ฉด true ๊ฐ’์„ ๊ฐ–์Šต๋‹ˆ๋‹ค.

<template>
  <todo-item is-completed></todo-item>
</template>

<script>
export default {
  props: ['isCompleted'],
  created() {
    console.log(this.isCompleted); // true
  }
}
</script>

7. ํ…œํ”Œ๋ฆฟ ํ‘œํ˜„์‹์—์„œ์˜ ํ”„๋กญ์Šค ์†์„ฑ ์ •์˜ ์ถ•์•ฝ ๋ฌธ๋ฒ•

์•„๋ž˜์™€ ๊ฐ™์ด data ์†์„ฑ ๊ฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ๋ชจ๋‘ ํ”„๋กญ์Šค ์†์„ฑ์œผ๋กœ ๊ฐ๊ฐ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ์ถ•์•ฝ ๋ฌธ๋ฒ•๋„ ๋“ฑ์žฅํ•˜์˜€์Šต๋‹ˆ๋‹ค.

<script>
export default {
  data() {
    return {
      appInfo: {
        title: '์ œ๋ชฉ',
        version: '๋ฒ„์ „'
      }
    }
  }
}
</script>
<!-- ์ถ•์•ฝ ๋ฌธ๋ฒ• -->
<app-title v-bind="appInfo"></app-title>
<!-- ์‹ค์ œ๋กœ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๋™์ž‘ - ๊ธฐ์กด ๋ฌธ๋ฒ• -->
<app-title v-bind:title="appInfo.title" v-bind:version="appInfo.version"></app-title>

8. ์ด๋ฒคํŠธ ์—๋ฐ‹ ๋ฌธ๋ฒ•

์ธ์Šคํ„ด์Šค ์˜ต์…˜ ์†์„ฑ์— emits ์˜ต์…˜ ์†์„ฑ์ด ์ถ”๊ฐ€ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

export default {
  // ์ธ์Šคํ„ด์Šค ์˜ต์…˜ ์†์„ฑ
  components: { TodoItem },
  emits: ['remove', 'add:todo']
}

์ปดํฌ๋„ŒํŠธ ๊ฐ„์— ์–ด๋–ค ๋ฐ์ดํ„ฐ์™€ ์ด๋ฒคํŠธ๊ฐ€ ์˜ค๊ฐ€๋Š”์ง€ ์ข€ ๋” ๋ช…ํ™•ํ•˜๊ฒŒ ์ธํ„ฐํŽ˜์ด์Šค(์•ฝ์†)๋ฅผ ๋ฌธ์„œํ™”ํ•˜๋Š” ๊ด€์ ์—์„œ ์ถ”๊ฐ€ํ•œ ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์•„๋ž˜์™€ ๊ฐ™์ด ์ด๋ฒคํŠธ ์—๋ฐ‹์— ๋Œ€ํ•œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ(validation) ๋ฌธ๋ฒ•๋„ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

export default {
  emits: {
    remove: false,
    'add:todo': ({ item }) => {
      if (item) {
        return true;
      } else {
        console.log('invalid event payload');
        return false;
      }
    }
  }
}

9. inheritAttrs ์˜ต์…˜ ์†์„ฑ

์„œ๋น„์Šค๋ฅผ ๊ฐœ๋ฐœํ•  ๋•Œ ์—ฌ๋Ÿฌ ๋ช…์˜ ํ”„๋ŸฐํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž๋ž‘ ํ˜‘์—…ํ•˜๋Š” ์ƒํ™ฉ์—์„œ ์œ ์šฉํ•  ๊ฒƒ์„ ๋ณด์ด๋Š” ์˜ต์…˜ ์†์„ฑ์ด ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ •์˜ํ•  ๋•Œ ์•„๋ž˜์™€ ๊ฐ™์ด ํ”„๋กญ์Šค ์†์„ฑ์ด ์•„๋‹Œ HTML ํ‘œ์ค€ ์†์„ฑ(Attributes)์„ ์ •์˜ํ•˜๋ฉด

<!-- App.vue - ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ -->
<template>
  <div>
    <todo-item class="warn"></todo-item>
  </div>
</template>

<!-- TodoItem.vue - ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ -->
<template>
  <li>
    <p>์•„์ดํ…œ 1</p>
  </li>
</template>

ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์ธ TodoItem ์ปดํฌ๋„ŒํŠธ์˜ HTML ๋ฃจํŠธ ์—˜๋ฆฌ๋จผํŠธ์— HTML ํ‘œ์ค€ ์†์„ฑ์ด ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์˜ ๋‚ด์šฉ์€ ์•„๋ž˜์™€ ๊ฐ™์ด ์ •์˜ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜๊ฒŒ๋˜์ฃ .

<!-- TodoItem.vue -->
<template>
  <li class="warn">
    <p>์•„์ดํ…œ 1</p>
  </li>
</template>

์ด๊ฑธ ์†์„ฑ ์ƒ์†(attribute inheritance)์ด๋ผ๊ณ  ํ•˜๋Š”๋ฐ ์•„๋ž˜์™€ ๊ฐ™์ด inheritAttrs: false๋ฅผ ์ฃผ์–ด์„œ ์ƒ์†์„ ๋ง‰๋Š” ๋ฌธ๋ฒ•์ด ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

export default {
  inheritAttrs: false
}

ํ˜‘์—… ์‹œ์— ๋ณดํ†ต ๊ณตํ†ต ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค์–ด๋†“๊ณ  ๊ณต์šฉ์œผ๋กœ ์“ฐ๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋Š”๋ฐ ์œ„์™€ ๊ฐ™์€ ์˜ต์…˜์„ ํ™œ์šฉํ•˜๋ฉด ๊ณตํ†ต ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ž˜๋ชป๋œ ๋ฐฉํ–ฅ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™๋„ค์š”.

10. v-model ๋ฌธ๋ฒ•

์‚ฌ์šฉ์ž ์ž…๋ ฅ์„ ๋ฐ›์„ ๋•Œ ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” v-model ๋””๋ ‰ํ‹ฐ๋ธŒ๋Š” ์ปดํฌ๋„ŒํŠธ ํƒœ๊ทธ์— ์—ฐ๊ฒฐํ•˜์˜€์„ ๋•Œ ์•„๋ž˜์™€ ๊ฐ™์ด ์ •์˜ํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. v-model ๋‚ด๋ถ€ ๋™์ž‘ ์„ค๋ช…ํ•˜๋Š” ๊ธ€ ๋งํฌ

<div>
  <my-input v-model="inputText"></my-input>
</div>
<template>
  <input :value="value" @input="onInput">
</template>

<script>
// MyInput.vue
export default {
  props: ['value'],
  methods: {
    onInput(event) {
      this.$emit('input', event.target.value);
    }
  }
}
</script>

์œ„ ๋ฌธ๋ฒ•์ด ์•„๋ž˜์™€ ๊ฐ™์ด ๋ฐ”๋€Œ์—ˆ์Šต๋‹ˆ๋‹ค.

<!-- App.vue -->
<template>
  <div>
    <my-input v-model="inputText"></my-input>
  </div>
</template>

<script>
export default {
  data() {
    return { inputText: '' }
  }
}
</script>
<!-- MyInput.vue -->
<template>
  <input :value="modelValue" @input="onInput">
</template>

<script>
export default {
  props: ['modelValue'],
  methods: {
    onInput(event) {
      this.$emit('update:modelValue', event.target.value);
    }
  }
}
</script>

ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ v-model์˜ ๋Œ€์ƒ์ด ๋˜๋Š” ํ”„๋กญ์Šค ์†์„ฑ ์ด๋ฆ„์ด modelValue๋กœ ๋ฐ”๋€Œ์—ˆ๊ณ , ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ๋กœ ์˜ฌ๋ฆด ๋•Œ์˜ ์ด๋ฒคํŠธ ๋˜ํ•œ input์ด ์•„๋‹ˆ๋ผ update:modelValue๋กœ ๋ฐ”๋€Œ์—ˆ์Šต๋‹ˆ๋‹ค.

  • :value -> :modelValue
  • :input -> :update:modelValue

11. ์ปดํฌ๋„ŒํŠธ ํƒœ๊ทธ์—์„œ v-model ์—ฌ๋Ÿฌ ๊ฐœ ์‚ฌ์šฉ

์ปดํฌ๋„ŒํŠธ ํƒœ๊ทธ์— ์•„๋ž˜์™€ ๊ฐ™์ด v-model ๋””๋ ‰ํ‹ฐ๋ธŒ๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

<!-- App.vue -->
<template>
  <div>
    <user-profile 
      v-model:firstName="firstName"
      v-model:lastName="lastName"
    ></user-profile>
  </div>
</template>

<script>
export default {
  data() {
    return { 
      firstName: '',
      lastName: ''
    }
  }
}
</script>
<!-- UserProfile.vue -->
<template>
  <input :value="firstName" @input="$emit('update:firstName', $event.target.value)">
  <input :value="lastName" @input="$emit('update:lastName', $event.target.value)">
</template>

<script>
export default {
  props: ['firstName', 'lastName'],
}
</script>

๊ณต์‹ ๋ฌธ์„œ์—์„œ ๊ผญ ์‚ดํŽด๋ณด๋ฉด ์ข‹์€ ๋‚ด์šฉ๋“ค

์œ„ ๋ฌธ๋ฒ• ์ด์™ธ์—๋„ ์•„๋ž˜ ๋‚ด์šฉ๋“ค์€ ๊ผญ ๊ณต์‹ ๋ฌธ์„œ์—์„œ ํ•œ๋ฒˆ์”ฉ ์ฝ์–ด๋ณด๋Š” ๊ฒƒ์„ ์ถ”์ฒœ๋“œ๋ฆฝ๋‹ˆ๋‹ค ๐Ÿ˜„

1. Computed Caching vs Methods

์ปดํ“จํ‹ฐ๋“œ ์†์„ฑ๊ณผ ๋ฉ”์„œ๋“œ์˜ ์ฐจ์ด์ ์„ ์ด์ „ ๊ณต์‹ ๋ฌธ์„œ๋ณด๋‹ค ๋” ์ ์ ˆํ•œ ์˜ˆ์ œ๋กœ ๋ช…์พŒํ•˜๊ฒŒ ์„ค๋ช…ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

2. Watch

Watch ์˜ˆ์ œ์™€ ์„ค๋ช…์€ ์—ฌ์ „ํžˆ ํ•œ๋ฒˆ์— ์™€๋‹ฟ์ง„ ์•Š์ง€๋งŒ ํ™•์ธํ•ด๋ณผ๋งŒ ํ•ฉ๋‹ˆ๋‹ค.

โ€œThis is most useful when you want to perform asynchronous or expensive operations in response to changing data.โ€

๊ฐœ์ธ์ ์ธ ์ƒ๊ฐ์œผ๋กœ๋Š” ์„œ๋น„์Šค ๊ฐœ๋ฐœํ•  ๋•Œ watch๋Š” ์ตœ์†Œ๋กœ ์‚ฌ์šฉํ•˜์ž๋Š” ์ฃผ์˜์ž…๋‹ˆ๋‹ค. watch๋ฅผ ์ ๊ฒŒ ์‚ฌ์šฉํ• ์ˆ˜๋ก ๋ฐ์ดํ„ฐ ๊ฐ„์˜ ์˜์กด ๊ด€๊ณ„ ๋ณต์žก๋„๋ฅผ ๋‚ฎ์ถ”๊ณ  ์ฝ”๋“œ ํ๋ฆ„์„ ๋” ์‰ฝ๊ฒŒ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋””๋ฒ„๊น…๋„ ์šฉ์ดํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

3. ํด๋ž˜์Šค ๋ฐ”์ธ๋”ฉ

๋ทฐ ๋ฐ์ดํ„ฐ ๊ฐ’์— ๋”ฐ๋ผ ํด๋ž˜์Šค๋ฅผ ๋™์ ์œผ๋กœ ๋ฐ”์ธ๋”ฉ ํ•˜๋Š” ๋ถ€๋ถ„์˜ ์˜ˆ์‹œ๊ฐ€ ์ž˜ ๋‚˜์™€ ์žˆ์Šต๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ๋„ ์‹ค๋ฌด์—์„œ ํ…œํ”Œ๋ฆฟ ํ‘œํ˜„์‹์„ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ๋งค์šฐ ์ง€ํ–ฅํ•˜๊ณ  ์žˆ๋Š” ์Šคํƒ€์ผ์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ผญ ํ™•์ธํ•ด๋ณด์‹œ๋Š” ๊ฑธ ์ถ”์ฒœ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

<div :class="classObject"></div>
data() {
  return {
    isActive: true,
    error: null
  }
},
computed: {
  classObject() {
    return {
      active: this.isActive && !this.error,
      'text-danger': this.error && this.error.type === 'fatal'
    }
  }
}

4. ์Šคํƒ€์ผ ๋ฐ”์ธ๋”ฉ

์ธ๋ผ์ธ ์Šคํƒ€์ผ์„ ํ•œ ์ค„๋กœ ๋Š˜์—ฌ๋†“๋Š” ๊ฒƒ๋ณด๋‹ค ์•„๋ž˜์™€ ๊ฐ™์ด ๊ฐ์ฒด ํ˜•ํƒœ๋กœ ์ž‘์—…ํ•˜๋ฉด ์ฝ”๋“œ๊ฐ€ ๊ฐ„๊ฒฐํ•ด์ง‘๋‹ˆ๋‹ค. ์‹ค๋ฌด์—์„œ ๋งŽ์ด๋“ค ๋†“์น˜๋Š” ๋ถ€๋ถ„์ธ ๊ฑฐ ๊ฐ™์€๋ฐ ์ž˜ ์งš์–ด์ฃผ์—ˆ๋„ค์š”.

<div :style="styleObject"></div>
data() {
  return {
    styleObject: {
      color: 'red',
      fontSize: '13px'
    }
  }
}

5. v-if์™€ v-show์˜ ์ฐจ์ด์ 

์„œ๋น„์Šค ๊ฐœ๋ฐœํ•  ๋•Œ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” v-if ๋””๋ ‰ํ‹ฐ๋ธŒ์™€ v-show ๋””๋ ‰ํ‹ฐ๋ธŒ์˜ ์ฐจ์ด์ ์„ ์ดˆ๊ธฐ ๋ Œ๋”๋ง ๋น„์šฉ๊ณผ ๋ณ€๊ฒฝ์‹œ ๋ Œ๋”๋ง ๋น„์šฉ์œผ๋กœ ๋‚˜๋ˆ„์–ด ์ž˜ ๋น„๊ตํ•˜์˜€์Šต๋‹ˆ๋‹ค.

6. ๋ชฉ๋ก ํ•„ํ„ฐ๋ง & ์˜ค๋”๋ง ํŒ

ํŠน์ • ๋ชฉ๋ก์„ ํ•„ํ„ฐ๋ง ๋ฐ ์˜ค๋”๋ง ํ•ด์•ผ ํ•  ๋•Œ computed์™€ methods๋ฅผ ์–ด๋–ป๊ฒŒ ๊ตฌ๋ถ„ํ•ด์„œ ์จ์•ผ ํ•˜๋Š” ์ง€ ์ž˜ ๊ธฐ์ˆ ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

7. v-on ๋””๋ ‰ํ‹ฐ๋ธŒ์˜ ์ด๋ฒคํŠธ ์ œ์–ด์ž(event modifiers)์— ๋Œ€ํ•œ ์ ์ ˆํ•œ ์˜ˆ์‹œ์™€ ์„ค๋ช…

prevent, stop, capture, self ๋“ฑ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๋ฐฉ์‹์— ๋Œ€ํ•œ ์˜ˆ์ œ์™€ ์ฃผ์„์ด ๊ธฐ์กด ๋ฌธ์„œ๋ณด๋‹ค ๋” ์™€๋‹ฟ๋„๋ก ์ž์„ธํ•˜๊ฒŒ ๊ธฐ์ˆ ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

8. ํ…œํ”Œ๋ฆฟ ํ‘œํ˜„์‹์— ์ด๋ฒคํŠธ ์ œ์–ด์ž๋ฅผ ์ ์šฉํ–ˆ์„ ๋•Œ์˜ ์žฅ์  ์„ค๋ช…

HTML ์ฝ”๋“œ์— ์ด๋ฒคํŠธ ์ œ์–ด ๋กœ์ง์ด ์•„๋ž˜์™€ ๊ฐ™์ด ๋ถ™์–ด ์žˆ๋Š”๊ฒŒ ์™œ ์žฅ์ ์ธ์ง€ ์ฝ”๋“œ ๊ฐ€๋…์„ฑ, ํ…Œ์ŠคํŒ…, ๋ฆฌํŒฉํ† ๋ง ๊ด€์ ์—์„œ ์ž˜ ์„ค๋ช…ํ•ด์ฃผ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

<button @click.prevent="doSomething">click me</button>

9. ์ปดํฌ๋„ŒํŠธ ๋“ฑ๋ก ๋ฐฉ์‹์˜ ๋น„๊ต

๋ทฐ 3 ๋ฌธ์„œ ๋Œ€๋ถ€๋ถ„์˜ ์ปดํฌ๋„ŒํŠธ ๊ด€๋ จ ์ฝ”๋“œ๋Š” ์ „์—ญ ์ปดํฌ๋„ŒํŠธ ์ฝ”๋“œ๋กœ ์˜ˆ์‹œ๋ฅผ ๋“ค๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์‹ค์ œ๋กœ ์„œ๋น„์Šค๋ฅผ ๊ตฌํ˜„ํ•  ๋•Œ๋Š” ์ฃผ๋กœ ๋กœ์ปฌ ์ปดํฌ๋„ŒํŠธ ๋ฐฉ์‹์ด ์‚ฌ์šฉ๋˜๋Š”๋ฐ ์ด์— ๋Œ€ํ•œ ์ฐจ์ด์ ์„ ์•„๋ž˜์™€ ๊ฐ™์ด ์ž˜ ์„ค๋ช…ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

โ€œ์ „์—ญ์œผ๋กœ ๋ทฐ ์ธ์Šคํ„ด์Šค์— ๋“ฑ๋กํ•  ๊ฒฝ์šฐ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋”๋ผ๋„ ์ตœ์ข… ๋นŒ๋“œ์— ํ•ด๋‹น ์ž์›์ด ํฌํ•จ๋œ๋‹ค. ๋”ฐ๋ผ์„œ ์‚ฌ์šฉ์ž๊ฐ€ ๋ถˆํ•„์š”ํ•œ ๋ฆฌ์†Œ์Šค๋ฅผ ๋‹ค์šด๋กœ๋“œ ๋ฐ›์•„์•ผ ํ•˜๋Š” ๋‹จ์ ์ด ์ƒ๊ธด๋‹ค.โ€

10. ์Šฌ๋กฏ์˜ ๋ Œ๋”๋ง ์œ ํšจ ๋ฒ”์œ„

์Šฌ๋กฏ์„ ํ™œ์šฉํ•  ๋•Œ ๋ฐ์ดํ„ฐ์˜ ์œ ํšจ ๋ฒ”์œ„๊ฐ€ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์™€ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ ์ค‘ ์–ด๋А ๊ณณ์— ์—ฐ๊ด€๋œ ๊ฑด์ง€ ๊ทธ๋ฆผ์œผ๋กœ ์ž˜ ํ’€์–ด ๋†“์•˜์Šต๋‹ˆ๋‹ค.

11. ๋ฏน์Šค์ธ

๋ฏน์Šค์ธ์˜ ๋‹จ์  2๊ฐ€์ง€๋ฅผ ์งš์œผ๋ฉด์„œ ์™œ Composition API๋ฅผ ์“ฐ๋ฉด ์ข‹์€์ง€์— ๋Œ€ํ•ด ์œ ๋„ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฏน์Šค์ธ์€ ๊ธฐ์กด ๋ทฐ ๋ฌธ๋ฒ•์ด๋‚˜ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์— ๋น„ํ•ด ๋‹ฌ๋ผ์ง„ ์ ์ด ์—†์œผ๋‹ˆ ์ฐธ๊ณ ํ•˜์‹œ๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค ๐Ÿ˜„

12. ๋ทฐ ํ…œํ”Œ๋ฆฟ ์ต์Šคํ”Œ๋กœ๋Ÿฌ

์—๋ฐ˜ ์œ ๊ฐ€ ์˜คํ”„๋ผ์ธ ์ˆ˜์—… ๋•Œ ์‚ฌ์šฉํ•˜๋˜ Vue Template Explorer๋ฅผ ์ด์ œ๋Š” ๊ณต์‹ ๋ฌธ์„œ์—์„œ๋„ ์•ˆ๋‚ดํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

13. ๋ทฐ ๋ฐ˜์‘์„ฑ(Reactivity) ์„ค๋ช…

๋ทฐ์˜ ๊ฐ•์ ์ธ ๋ฐ˜์‘์„ฑ ์ฒด๊ณ„(Reactivity System)๋ฅผ ์—‘์…€์— ๋น„์œ ํ•˜๋ฉด์„œ โ€œ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ํ™”๋ฉด์ด ๊ฐฑ์‹ ๋œ๋‹คโ€ ๋ผ๋Š” ๊ฑธ๋กœ ์ž˜ ์„ค๋ช…ํ•˜๊ณ  ์žˆ๋„ค์š” ๐Ÿ˜„

๋งˆ๋ฌด๋ฆฌ

์ง€๊ธˆ๊นŒ์ง€ Vue 3์—์„œ ๊ธฐ์กด ๋ฒ„์ „๊ณผ ๋น„๊ตํ•˜์—ฌ ๋‹ฌ๋ผ์ง„ ์ ๊ณผ ์ถ”๊ฐ€์ ์œผ๋กœ ์ œ๊ณต๋˜๋Š” ๋ฌธ๋ฒ•๋“ค์— ๋Œ€ํ•ด์„œ ๊ฐ„๋žตํžˆ ์‚ดํŽด๋ดค์Šต๋‹ˆ๋‹ค. ๊ธฐ์กด ํ•œ๊ณ„์ ์„ ๊ทน๋ณตํ•˜๋ ค๋Š” ๋…ธ๋ ฅ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์‹ค๋ฌด์—์„œ ๋งŽ์ด ์‚ฌ์šฉ๋˜๊ณ  ์žˆ๋Š” ๋ฌธ๋ฒ•์— ๋Œ€ํ•ด์„œ ๋‹ค์–‘ํ•œ ์„ ํƒ์ง€๋ฅผ ์ œ๊ณตํ•ด ์ค€ ๊ฒƒ์ด ๋ˆˆ์— ๋„๋„ค์š”.

๋ฌด์—‡๋ณด๋‹ค๋„ ๊ธฐ์—…์— ์ข…์†๋˜์–ด ์žˆ์ง€ ์•Š์€ 100% ์ปค๋ฎค๋‹ˆํ‹ฐ ์˜คํ”ˆ์†Œ์Šค๋‹ต๊ฒŒ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์—…๋ฐ์ดํŠธ ๋ฐฉํ–ฅ์„ฑ์„ ์‚ฌ์šฉ์ž๋“ค๊ณผ ๊ต๊ฐํ•˜๋ฉฐ ๋ฐœ์ „์‹œ์ผœ ์™”๋‹ค๋Š” ๊ฒŒ ๊ฐ€์žฅ ์ธ์ƒ์ ์ด๋„ค์š”. ์•ž์œผ๋กœ๋„ ๋” ๋งŽ์€ ๋ถ„๋“ค์ด Vue.js ์˜คํ”ˆ ์†Œ์Šค ๊ฐœ๋ฐœ์— ์ฐธ์—ฌํ•ด์„œ ๋” ์ข‹์€ ๋„๊ตฌ๋ฅผ ํ•จ๊ป˜ ๋งŒ๋“ค์–ด ๋‚˜๊ฐˆ ์ˆ˜ ์žˆ์œผ๋ฉด ์ข‹๊ฒ ์Šต๋‹ˆ๋‹ค.

Vue 3์— ๋Œ€ํ•ด์„œ ๋ณธ๊ฒฉ์ ์œผ๋กœ ํŒŒํ—ค์ณ ๋ณผ ๋‹ค์Œ ๊ธ€๋“ค๋„ ๊ธฐ๋Œ€ํ•ด ์ฃผ์„ธ์š”. ๊ธด ๊ธ€ ์ฝ์–ด ์ฃผ์…”์„œ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค ๐Ÿ˜„

Vue 3 ํ•™์Šต ๋กœ๋“œ๋งต

Vue 3 ์™„๋ฒฝ ๋งˆ์Šคํ„ฐ ๋กœ๋“œ๋งต / Vue + TypeScript ํ•™์Šต ๋กœ๋“œ๋งต / React + TypeScript ํ•™์Šต ๋กœ๋“œ๋งต

๊ธ€๋ณด๋‹ค ๋” ์‰ฝ๊ฒŒ ๋ฐฐ์šฐ๋Š” ์˜จ๋ผ์ธ ๊ฐ•์˜

์ข€ ๋” ์นœ์ ˆํ•˜๊ณ  ์ƒ์„ธํ•œ ์„ค๋ช…์„ ์›ํ•˜์‹ ๋‹ค๋ฉด ์•„๋ž˜ ๊ฐ•์ขŒ๋ฅผ ์ด์šฉํ•ด๋ณด์‹œ๋Š” ๊ฒƒ๋„ ์ข‹์„ ๊ฒƒ ๊ฐ™์•„์š” ๐Ÿ˜„

์ธํ”„๋Ÿฐ ์˜จ๋ผ์ธ ๊ฐ•์˜ : Vue 3 ์‹œ์ž‘ํ•˜๊ธฐ / Vue.js ์‹œ์ž‘ํ•˜๊ธฐ(Vue 2) / Vue.js ์ค‘๊ธ‰
์ธํ”„๋Ÿฐ ์˜จ๋ผ์ธ ๊ฐ•์˜ : Vue.js ์™„๋ฒฝ ๊ฐ€์ด๋“œ / Vue.js ๋์žฅ๋‚ด๊ธฐ / ํ”„๋ŸฐํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž๋ฅผ ์œ„ํ•œ ์›นํŒฉ
์ธํ”„๋Ÿฐ ์˜จ๋ผ์ธ ๊ฐ•์˜ : ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ž…๋ฌธ / ์‹ค์ „ ํ”„๋กœ์ ํŠธ๋กœ ๋ฐฐ์šฐ๋Š” ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ / Vue.js + TypeScript ์™„๋ฒฝ ๊ฐ€์ด๋“œ

ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์„ ๋” ์ž˜ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•

์บกํ‹ดํŒ๊ต์˜ ๋†์ถ•๋œ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ง€์‹๊ณผ ๋…ธํ•˜์šฐ๋ฅผ ์•Œ๊ณ  ์‹ถ๋‹ค๋ฉด ์•„๋ž˜ ๋„์„œ๋ฅผ ์ฝ์–ด๋ณด์„ธ์š” :)

์‰ฝ๊ฒŒ ์‹œ์ž‘ํ•˜๋Š” ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ๋„์„œ