Composition API RFC - ChoDragon9/posts GitHub Wiki


title: Composition API RFC ๋ฒˆ์—ญ sidebar: auto

::: warning Composition API ํ•™์Šต์„ ์œ„ํ•ด Composition API RFC์„ ๋ฒˆ์—ญํ•œ ํฌ์ŠคํŠธ์ž…๋‹ˆ๋‹ค. ๊ณต์‹ ๋ฌธ์„œ๊ฐ€ ์•„๋‹˜์„ ๋ฐํž™๋‹ˆ๋‹ค. :::

::: tip RFC(Request for Comments) ๋ฌธ์„œ๋Š” ๋น„ํ‰์„ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋ฌธ์„œ๋ผ๋Š” ์˜๋ฏธ๋กœ, ์ปดํ“จํ„ฐ ๋„คํŠธ์›Œํฌ ๊ณตํ•™ ๋“ฑ์—์„œ ์ธํ„ฐ๋„ท ๊ธฐ์ˆ ์— ์ ์šฉ ๊ฐ€๋Šฅํ•œ ์ƒˆ๋กœ์šด ์—ฐ๊ตฌ, ํ˜์‹ , ๊ธฐ๋ฒ• ๋“ฑ์„ ์•„์šฐ๋ฅด๋Š” ๋ฉ”๋ชจ๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค.

์š”์•ฝ

์ปดํฌ์ง€์…˜ API ์†Œ๊ฐœ: ์ปดํฌ๋„ŒํŠธ ๋กœ์ง์„ ์œ ์—ฐํ•˜๊ฒŒ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๋ถ€๊ฐ€์ ์ธ ํ•จ์ˆ˜๊ธฐ๋ฐ˜ API ์„ธํŠธ์ž…๋‹ˆ๋‹ค.

๊ธฐ์ดˆ ์˜ˆ์ œ

<template>
  <button @click="increment">
    Count is: {{ state.count }}, double is: {{ state.double }}
  </button>
</template>

<script>
import { reactive, computed } from 'vue'

export default {
  setup() {
    const state = reactive({
      count: 0,
      double: computed(() => state.count * 2)
    })

    function increment() {
      state.count++
    }

    return {
      state,
      increment
    }
  }
}
</script>

๋™๊ธฐ ๋ถ€์—ฌ

๋กœ์ง ์žฌ์‚ฌ์šฉ & ์ฝ”๋“œ ๊ตฌ์„ฑ

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

  1. ๋ณต์žกํ•œ ์ปดํฌ๋„ŒํŠธ์˜ ์ฝ”๋“œ๋Š” ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ ๊ธฐ๋Šฅ์ด ์ฆ๊ฐ€ํ•จ์— ๋”ฐ๋ผ ์ถ”๋ก ํ•˜๊ธฐ ๋” ์–ด๋ ค์›Œ์ง‘๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ํŠนํžˆ ๊ฐœ๋ฐœ์ž๊ฐ€ ์Šค์Šค๋กœ ์ž‘์„ฑํ•˜์ง€ ์•Š์€ ์ฝ”๋“œ๋ฅผ ์ฝ์„ ๋•Œ ๊ฒฝ์šฐ์— ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๊ทผ๋ณธ ์›์ธ์€ Vue์˜ ๊ธฐ์กด API๊ฐ€ ์˜ต์…˜๋ณ„๋กœ ์ฝ”๋“œ ๊ตฌ์„ฑ์„ ๊ฐ•์š”ํ•˜์ง€๋งŒ ๊ฒฝ์šฐ์— ๋”ฐ๋ผ ๋…ผ๋ฆฌ์  ๋ฌธ์ œ๋กœ ์ฝ”๋“œ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ์ด ๋” ํ•ฉ๋ฆฌ์ ์ž…๋‹ˆ๋‹ค.
  2. ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๊ฐ„์— ๋…ผ๋ฆฌ๋ฅผ ์ถ”์ถœํ•˜๊ณ  ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๊นจ๋—ํ•˜๊ณ  ๋น„์šฉ์ด ๋“ค์ง€ ์•Š๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ์—†์Šต๋‹ˆ๋‹ค. (๋…ผ๋ฆฌ ์ถ”์ถœ ๋ฐ ์žฌ์‚ฌ์šฉ์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ)

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

๋” ์ข‹์€ ํƒ€์ž… ์ถ”๋ก 

๋Œ€๊ทœ๋ชจ ํ”„๋กœ์ ํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฐœ๋ฐœ์ž์˜ ๋˜ ๋‹ค๋ฅธ ์ผ๋ฐ˜์ ์ธ ๊ธฐ๋Šฅ ์š”์ฒญ์€ ๋” ๋‚˜์€ TypeScript ์ง€์›์ž…๋‹ˆ๋‹ค. Vue์˜ ํ˜„์žฌ API๋Š” TypeScript์™€์˜ ํ†ตํ•ฉ๊ณผ ๊ด€๋ จํ•˜์—ฌ Vue์˜ ์†์„ฑ์„ ๋…ธ์ถœํ•˜๊ธฐ ์œ„ํ•ด ๋‹จ์ผ this ์ปจํ…์ŠคํŠธ์— ์˜์กดํ•˜๊ณ  Vue ์ปดํฌ๋„ŒํŠธ์—์„œ this ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์•ฝ๊ฐ„ ๋” ๋งŽ๊ธฐ ๋•Œ๋ฌธ์— ๋ช‡ ๊ฐ€์ง€ ๋ฌธ์ œ๋ฅผ ์ œ๊ธฐํ–ˆ์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜ JavaScript ๋ณด๋‹ค ๋งˆ์ˆ ์ ์ž…๋‹ˆ๋‹ค. (์˜ˆ: methods ์•„๋ž˜์— ์ค‘์ฒฉ๋œ ํ•จ์ˆ˜์˜ this ๋Š” methods ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ์•„๋‹Œ ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€๋ฆฌ ํ‚ต๋‹ˆ๋‹ค). ์ฆ‰, Vue์˜ ๊ธฐ์กด API๋Š” ๋‹จ์ˆœํžˆ ํƒ€์ž… ์ถ”๋ก ๋ฅผ ์—ผ๋‘์— ๋‘๊ณ  ์„ค๊ณ„๋˜์ง€ ์•Š์•˜์œผ๋ฉฐ TypeScript์™€ ์ž˜ ์ž‘๋™ํ•˜๋„๋ก ๋งŒ๋“ค ๋•Œ ๋งŽ์€ ๋ณต์žก์„ฑ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

์˜ค๋Š˜๋‚  Vue๋ฅผ TypeScript์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€๋ถ€๋ถ„์˜ ์‚ฌ์šฉ์ž๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ๋„์›€์„ ๋ฐ›์•„ ์ปดํฌ๋„ŒํŠธ๋ฅผ TypeScript ํด๋ž˜์Šค๋กœ ์ œ์ž‘ํ•  ์ˆ˜ ์žˆ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ธ vue-class-component ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. 3.0์„ ์„ค๊ณ„ํ•˜๋Š” ๋™์•ˆ ์ด์ „ (๋“œ๋กญ๋œ) RFC์—์„œ ์ž…๋ ฅ ๋ฌธ์ œ๋ฅผ ๋ณด๋‹ค ํšจ๊ณผ์ ์œผ๋กœ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋‚ด์žฅ ํด๋ž˜์Šค API๋ฅผ ์ œ๊ณตํ•˜๋ ค๊ณ  ์‹œ๋„ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์„ค๊ณ„์— ๋Œ€ํ•ด ๋…ผ์˜ํ•˜๊ณ  ๋ฐ˜๋ณตํ•˜๋ฉด์„œ ํด๋ž˜์Šค API๊ฐ€ ํƒ€์ดํ•‘ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์— ์˜์กดํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•˜์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๊ตฌํ˜„ ์„ธ๋ถ€ ์‚ฌํ•ญ์— ๋Œ€ํ•ด ๋งŽ์€ ๋ถˆํ™•์‹ค์„ฑ์ด ์žˆ๋Š” ๋งค์šฐ ๋ถˆ์•ˆ์ •ํ•œ 2๋‹จ๊ณ„ ์ œ์•ˆ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๊ธฐ๋ฐ˜์„ ์„ธ์šฐ๋Š” ๋ฐ ๋‹ค์†Œ ์œ„ํ—˜ํ•œ ํ† ๋Œ€๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. (ํด๋ž˜์Šค API ํƒ€์ž… ๋ฌธ์ œ์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์—ฌ๊ธฐ)

์ด์— ๋น„ํ•ด์„œ, ์ด RFC์—์„œ ์ œ์•ˆ ๋œ API๋Š” ๋Œ€๋ถ€๋ถ„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์นœ์ˆ™ํ•œ ์ผ๋ฐ˜ ๋ณ€์ˆ˜์™€ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ œ์•ˆ ๋œ API๋กœ ์ž‘์„ฑ๋œ ์ฝ”๋“œ๋Š” ๋ฉ”๋‰ด์–ผ ํƒ€์ž… ํžŒํŠธ๊ฐ€ ๊ฑฐ์˜ ํ•„์š”์—†๋Š” ์™„์ „ํ•œ ํƒ€์ž… ์ถ”๋ก ์„ ์ฆ๊ธธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์ œ์•ˆ ๋œ API๋กœ ์ž‘์„ฑ๋œ ์ฝ”๋“œ๊ฐ€ TypeScript์™€ ์ผ๋ฐ˜ JavaScript์—์„œ ๊ฑฐ์˜ ๋™์ผํ•˜๊ฒŒ ๋ณด์ผ ๊ฒƒ์ด๋ฏ€๋กœ TypeScript๊ฐ€ ์•„๋‹Œ ์‚ฌ์šฉ์ž๋„ ๋” ๋‚˜์€ IDE ์ง€์›์„ ์œ„ํ•ด ํƒ€์ดํ•‘์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

์ƒ์„ธ ์„ค๊ณ„

API ์†Œ๊ฐœ

์—ฌ๊ธฐ์—์„œ ์ œ์•ˆ๋˜๋Š” API๋Š” ์ƒˆ๋กœ์šด ๊ฐœ๋…์„ ๋„์ž…ํ•˜๋Š” ๋Œ€์‹  ๋ฐ˜์‘ ์ƒํƒœ ์ƒ์„ฑ ๋ฐ ๊ด€์ฐฐ๊ณผ ๊ฐ™์€ Vue์˜ ํ•ต์‹ฌ ๊ธฐ๋Šฅ์„ ๋…๋ฆฝํ˜• ํ•จ์ˆ˜๋กœ ๋…ธ์ถœํ•˜๋Š” ๊ฒƒ์— ๊ด€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ API๋ฅผ ์†Œ๊ฐœํ•˜๊ณ  ์ปดํฌ๋„ŒํŠธ ๋กœ์ง์„ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด 2.x ์˜ต์…˜ ๋Œ€์‹  ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค. ์ด ์„น์…˜์€ ๊ธฐ๋ณธ ์•„์ด๋””์–ด๋ฅผ ์†Œ๊ฐœํ•˜๋Š” ๋ฐ ์ค‘์ ์„ ๋‘๋ฏ€๋กœ ๊ฐ API์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋‹ค๋ฃจ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ „์ฒด API ์‚ฌ์šฉ์€ API Reference ์„น์…˜์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐ˜์‘ํ˜• ์ƒํƒœ์™€ ๋ถ€์ˆ˜ํšจ๊ณผ

๊ฐ„๋‹จํ•œ ์ž‘์—…๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค: ์ผ๋ถ€ ๋ฐ˜์‘ ์ƒํƒœ ์„ ์–ธ.

import { reactive } from 'vue'

// reactive state
const state = reactive({
  count: 0
})

reactive ๋Š” 2.x์˜ ํ˜„์žฌ Vue.observable() API์™€ ๋™์ผํ•˜๋ฉฐ RxJS Observables๊ณผ ํ˜ผ๋™๋˜์ง€ ์•Š๋„๋ก ์ด๋ฆ„์„ ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ๋ฐ˜ํ™˜๋œ ์ƒํƒœ๋Š” ๋ชจ๋“  Vue ์‚ฌ์šฉ์ž์—๊ฒŒ ์นœ์ˆ™ํ•ด์•ผ ํ•˜๋Š” ๋ฐ˜์‘ํ˜• ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค.

Vue์—์„œ ๋ฐ˜์‘ํ˜• ์ƒํƒœ์˜ ํ•„์ˆ˜ ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ๋ Œ๋”๋ง ์ค‘์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ข…์†์„ฑ ์ถ”์  ๋•๋ถ„์— ๋ฐ˜์‘ํ˜• ์‚ฌํƒœ๊ฐ€ ๋ณ€๊ฒฝ ๋  ๋•Œ ๋ทฐ๊ฐ€ ์ž๋™์œผ๋กœ ์—…๋ฐ์ดํŠธ๋ฉ๋‹ˆ๋‹ค. DOM์—์„œ ๋ฌด์–ธ๊ฐ€๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ๊ฒƒ์€ "๋ถ€์ˆ˜ํšจ๊ณผ"๋กœ ๊ฐ„์ฃผ๋ฉ๋‹ˆ๋‹ค: ์šฐ๋ฆฌ์˜ ํ”„๋กœ๊ทธ๋žจ์€ ํ”„๋กœ๊ทธ๋žจ ์ž์ฒด(DOM) ์™ธ๋ถ€์˜ ์ƒํƒœ๋ฅผ ์ˆ˜์ •ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ˜์‘ํ˜• ์ƒํƒœ์— ๋”ฐ๋ผ ๋ถ€์ˆ˜ํšจ๊ณผ๋ฅผ ์ ์šฉํ•˜๊ณ  ์ž๋™์œผ๋กœ ๋‹ค์‹œ ์ ์šฉํ•˜๋ ค๋ฉด watchEffect API๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import { reactive, watchEffect } from 'vue'

const state = reactive({
  count: 0
})

watchEffect(() => {
  document.body.innerHTML = `count is ${state.count}`
})

watchEffect ๋Š” ์›ํ•˜๋Š” ๋ถ€์ˆ˜ํšจ๊ณผ๋ฅผ ์ ์šฉํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค (์ด ๊ฒฝ์šฐ innerHTML ์„ค์ •). ํ•จ์ˆ˜๋ฅผ ์ฆ‰์‹œ ์‹คํ–‰ํ•˜๊ณ  ์‹คํ–‰ ์ค‘์— ์‚ฌ์šฉํ•œ ๋ชจ๋“  ๋ฐ˜์‘ ์ƒํƒœ ์†์„ฑ์„ ์ข…์†์„ฑ์œผ๋กœ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ state.count ๋Š” ์ดˆ๊ธฐ ์‹คํ–‰ ํ›„์ด ๊ฐ์‹œ์ž์— ๋Œ€ํ•œ ์ข…์†์„ฑ์œผ๋กœ ์ถ”์ ๋ฉ๋‹ˆ๋‹ค. ์•ž์œผ๋กœ state.count ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ๋‚ด๋ถ€ ํ•จ์ˆ˜๊ฐ€ ๋‹ค์‹œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด Vue์˜ ๋ฐ˜์‘ํ˜• ์‹œ์Šคํ…œ์˜ ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ์˜ data()์—์„œ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด ๋‚ด๋ถ€์ ์œผ๋กœ reactive()์— ์˜ํ•ด ๋ฐ˜์‘์ด ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค. ํ…œํ”Œ๋ฆฟ์€ ์ด๋Ÿฌํ•œ ๋ฐ˜์‘ํ˜• ์†์„ฑ์„ ์‚ฌ์šฉํ•˜๋Š” ๋ Œ๋”๋ง ํ•จ์ˆ˜ (๋ณด๋‹ค ํšจ์œจ์ ์ธ innerHTML๋กœ ์ƒ๊ฐ)๋กœ ์ปดํŒŒ์ผ ๋ฉ๋‹ˆ๋‹ค.

watchEffect ๋Š” 2.x watch ์˜ต์…˜๊ณผ ์œ ์‚ฌํ•˜์ง€๋งŒ ๊ฐ์‹œ๋œ ๋ฐ์ดํ„ฐ ์†Œ์Šค์™€ ๋ถ€์ˆ˜ํšจ๊ณผ ์ฝœ๋ฐฑ์„ ๋ถ„๋ฆฌํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. Composition API๋Š” 2.x ์˜ต์…˜๊ณผ ์ •ํ™•ํžˆ ๋™์ผํ•œ ๋™์ž‘์„ ํ•˜๋Š” watch ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์œ„์˜ ์˜ˆ์ œ๋ฅผ ๊ณ„์†ํ•˜๋ฉด ์‚ฌ์šฉ์ž ์ž…๋ ฅ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

function increment() {
  state.count++
}

document.body.addEventListener('click', increment)

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

import { reactive, watchEffect } from 'vue'

const state = reactive({
  count: 0
})

function increment() {
  state.count++
}

const renderContext = {
  state,
  increment
}

watchEffect(() => {
  // hypothetical internal code, NOT actual API
  renderTemplate(
    `<button @click="increment">{{ state.count }}</button>`,
    renderContext
  )
})

๊ณ„์‚ฐ๋œ ์ƒํƒœ์™€ Refs

๋•Œ๋•Œ๋กœ ์šฐ๋ฆฌ๋Š” ๋‹ค๋ฅธ ์ƒํƒœ์— ์˜์กดํ•˜๋Š” ์ƒํƒœ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. Vue์—์„œ๋Š” ๊ณ„์‚ฐ๋œ ์†์„ฑ ์œผ๋กœ ์ฒ˜๋ฆฌ ๋ฉ๋‹ˆ๋‹ค. ๊ณ„์‚ฐ๋œ ๊ฐ’์„ ์ง์ ‘ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด computed API๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค :

import { reactive, computed } from 'vue'

const state = reactive({
  count: 0
})

const double = computed(() => state.count * 2)

computed ๋ž€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ๋‚ด๋ถ€์—์„œ computed ์ด ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„๋˜๋Š” ์ง€ ์ถ”์ธกํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// ๋‹จ์ˆœํ™”๋œ ์˜์‚ฌ ์ฝ”๋“œ
function computed(getter) {
  let value
  watchEffect(() => {
    value = getter()
  })
  return value
}

๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ๋Š” ์ด๊ฒƒ์ด ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ์••๋‹ˆ๋‹ค: ๋งŒ์•ฝ value ๊ฐ€ number ์™€ ๊ฐ™์€ ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ ํƒ€์ž…์ด๋ผ๋ฉด, computed ๋‚ด๋ถ€์˜ ์—…๋ฐ์ดํŠธ ๋กœ์ง์— ๋Œ€ํ•œ ์—ฐ๊ฒฐ์€ ๋ฐ˜ํ™˜๋˜๋ฉด ์†์‹ค ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋Š” JavaScript ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ ํƒ€์ž…์ด ์ฐธ์กฐ๊ฐ€ ์•„๋‹Œ ๊ฐ’์œผ๋กœ ์ „๋‹ฌ๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

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

// ๋‹จ์ˆœํ™”๋œ ์˜์‚ฌ ์ฝ”๋“œ
function computed(getter) {
  const ref = {
    value: null
  }
  watchEffect(() => {
    ref.value = getter()
  })
  return ref
}

๋˜ํ•œ ์˜์กด์„ฑ ์ถ”์  ๋ฐ ๋ณ€๊ฒฝ ์•Œ๋ฆผ์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ๊ฐ์ฒด์˜ .value ์†์„ฑ์— ๋Œ€ํ•œ ์ฝ๊ธฐ/์“ฐ๊ธฐ ์ž‘์—…์„ ๊ฐ€๋กœ ์ฑŒ ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค (๊ฐ„๋‹จํ•˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด ์ฝ”๋“œ๋ฅผ ์ƒ๋žต). ์ด์ œ ๋ฐ˜์‘์„ฑ ์†์‹ค์— ๋Œ€ํ•œ ๊ฑฑ์ •์—†์ด ๊ณ„์‚ฐ๋œ ๊ฐ’์„ ์ฐธ์กฐ๋กœ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹จ์ ์€ ์ตœ์‹ ๊ฐ’์„ ๊ฒ€์ƒ‰ํ•˜๊ธฐ ์œ„ํ•ด ์ด์ œ .value ๋ฅผ ํ†ตํ•ด ๊ฐ’์„ ์ ‘๊ทผํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

const double = computed(() => state.count * 2)

watchEffect(() => {
  console.log(double.value)
}) // -> 0

state.count++ // -> 2

์—ฌ๊ธฐ์—์„œ double์€ ๋ณด์œ ํ•˜๊ณ  ์žˆ๋Š” ๋‚ด๋ถ€๊ฐ’์— ๋Œ€ํ•œ ๋ฐ˜์‘์„ฑ ์ฐธ์กฐ๋กœ ์‚ฌ์šฉ๋˜๋ฏ€๋กœ "ref"๋ผ๊ณ  ํ•˜๋Š” ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค.

Vue์—๋Š” ์ด๋ฏธ "refs"๋ผ๋Š” ๊ฐœ๋…์ด ์žˆ์ง€๋งŒ ํ…œํ”Œ๋ฆฟ์—์„œ DOM ์š”์†Œ ๋˜๋Š” ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๊ฒฝ์šฐ์—๋งŒ ํ•ด๋‹น๋ฉ๋‹ˆ๋‹ค ("template refs"). ์—ฌ๊ธฐ์—์„œ ์ƒˆ๋กœ์šด refs ์‹œ์Šคํ…œ์ด ๋…ผ๋ฆฌ์ ์ธ ์ƒํƒœ ๋ฐ ํ…œํ”Œ๋ฆฟ refs์— ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉ ๋  ์ˆ˜ ์žˆ๋Š” ์ง€ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค.

๊ณ„์‚ฐ๋œ refs์™ธ์—, ref API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ผ๋ฐ˜ ๊ฐ€๋ณ€ ์ฐธ์กฐ๋ฅผ ์ง์ ‘ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

const count = ref(0)
console.log(count.value) // 0

count.value++
console.log(count.value) // 1

์ฐธ์กฐ ์–ธ๋ž˜ํ•‘

๋ Œ๋” ์ปจํ…์ŠคํŠธ์—์„œ ref๋ฅผ ์†์„ฑ์œผ๋กœ ๋…ธ์ถœ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด๋ถ€์ ์œผ๋กœ Vue๋Š” ๋ Œ๋” ์ปจํ…์ŠคํŠธ์—์„œ ref๊ฐ€ ๋ฐœ์ƒํ•  ๋•Œ ์ปจํ…์ŠคํŠธ๊ฐ€ ๋‚ด๋ถ€๊ฐ’์„ ์ง์ ‘ ๋…ธ์ถœํ•˜๋„๋ก ref์— ๋Œ€ํ•ด ํŠน๋ณ„ํ•œ ์ฒ˜๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ํ…œํ”Œ๋ฆฟ์—์„œ count.value ๋Œ€์‹  count ๋ฅผ ์ง์ ‘ ์“ธ ์ˆ˜ ์žˆ์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ์€ reactive ๋Œ€์‹  ref ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋™์ผํ•œ ์นด์šดํ„ฐ ์˜ˆ์ œ์˜ ๋ฒ„์ „์ž…๋‹ˆ๋‹ค.

import { ref, watch } from 'vue'

const count = ref(0)

function increment() {
  count.value++
}

const renderContext = {
  count,
  increment
}

watchEffect(() => {
  renderTemplate(
    `<button @click="increment">{{ count }}</button>`,
    renderContext
  )
})

๋˜ํ•œ ์ฐธ์กฐ๊ฐ€ ๋ฐ˜์‘ ๊ฐ์ฒด ์•„๋ž˜์— ์†์„ฑ์œผ๋กœ ์ค‘์ฒฉ๋˜๋ฉด ์ ‘๊ทผ ์‹œ ์ž๋™์œผ๋กœ ๋ž˜ํ•‘๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

const state = reactive({
  count: 0,
  double: computed(() => state.count * 2)
})

// `state.double.value` ๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
console.log(state.double)

์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ ์‚ฌ์šฉ๋ฐฉ๋ฒ•

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

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

function setup() {
  const state = reactive({
    count: 0,
    double: computed(() => state.count * 2)
  })

  function increment() {
    state.count++
  }

  return {
    state,
    increment
  }
}

const renderContext = setup()

watchEffect(() => {
  renderTemplate(
    `<button @click="increment">
      Count is: {{ state.count }}, double is: {{ state.double }}
    </button>`,
    renderContext
  )
})

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

์ด์ œ setup() ํ˜ธ์ถœ, ๊ฐ์‹œ์ž ์ƒ์„ฑ ๋ฐ ํ…œํ”Œ๋ฆฟ์„ ํ”„๋ ˆ์ž„์›Œํฌ๋กœ ๋ Œ๋”๋ง ํ•˜๋Š” ์ž‘์—…์„ ๋งˆ์น˜๋ฉด setup() ํ•จ์ˆ˜์™€ ํ…œํ”Œ๋ฆฟ๋งŒ์œผ๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ •์˜ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

<template>
  <button @click="increment">
    Count is: {{ state.count }}, double is: {{ state.double }}
  </button>
</template>

<script>
import { reactive, computed } from 'vue'

export default {
  setup() {
    const state = reactive({
      count: 0,
      double: computed(() => state.count * 2)
    })

    function increment() {
      state.count++
    }

    return {
      state,
      increment
    }
  }
}
</script>

์ด๊ฒƒ์€ ์šฐ๋ฆฌ๊ฐ€ ์ž˜ ์•Œ๊ณ  ์žˆ๋Š” ๋‹จ์ผ ํŒŒ์ผ ์ปดํฌ๋„ŒํŠธ ํ˜•์‹์ด๋ฉฐ ๋…ผ๋ฆฌ ํ˜•์‹(<script>) ๋งŒ ๋‹ค๋ฅธ ํ˜•์‹์œผ๋กœ ํ‘œํ˜„๋ฉ๋‹ˆ๋‹ค. ํ…œํ”Œ๋ฆฟ ๊ตฌ๋ฌธ์€ ๊ทธ๋Œ€๋กœ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค. <script> ์€ ์ƒ๋žต๋˜์—ˆ์ง€๋งŒ ์ •ํ™•ํžˆ ๋™์ผํ•˜๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

๋ผ์ดํ”„์‚ฌ์ดํด ํ›…

์ง€๊ธˆ๊นŒ์ง€ ์ปดํฌ๋„ŒํŠธ์˜ ์ˆœ์ˆ˜ํ•œ ์ƒํƒœ ์ธก๋ฉด์ธ ์‚ฌ์šฉ์ž ์ƒํƒœ์˜ ๋ฐ˜์‘ ์ƒํƒœ, ๊ณ„์‚ฐ๋œ ์ƒํƒœ ๋ฐ ๋ณ€๊ฒฝ ์ƒํƒœ์— ๋Œ€ํ•ด ์‚ดํŽด ๋ณด์•˜์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ปดํฌ๋„ŒํŠธ๋Š” ๋ถ€์ˆ˜ํšจ๊ณผ๋ฅผ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค (์˜ˆ: ์ฝ˜์†” ๋กœ๊น…, ajax ์š”์ฒญ ์ „์†ก ๋˜๋Š” window ์—์„œ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ์„ค์ •). ์ด๋Ÿฌํ•œ ๋ถ€์ˆ˜ํšจ๊ณผ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๋‹ค์Œ ํƒ€์ด๋ฐ์— ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค.

  • ์ƒํƒœ๊ฐ€ ๋ณ€ํ•  ๋•Œ
  • ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งˆ์šดํŠธ, ์—…๋ฐ์ดํŠธ ๋˜๋Š” ๋งˆ์šดํŠธ ํ•ด์ œ ๋  ๋•Œ(๋ผ์ดํ”„์‚ฌ์ดํด ํ›…)

์šฐ๋ฆฌ๋Š” watchEffect ์™€ watch API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒํƒœ ๋ณ€ํ™”์— ๋”ฐ๋ผ ๋ถ€์ˆ˜ํšจ๊ณผ๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์„œ๋กœ ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ์‚ฌ์ดํด ํ›…์—์„œ ๋ถ€์ˆ˜ํšจ๊ณผ๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์ „์šฉ onXXX API(๊ธฐ์กด ๋ผ์ดํ”„์‚ฌ์ดํด ์˜ต์…˜์„ ์ง์ ‘ ๋ฏธ๋Ÿฌ๋ง)๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import { onMounted } from 'vue'

export default {
  setup() {
    onMounted(() => {
      console.log('component is mounted!')
    })
  }
}

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

์ด๋Ÿฌํ•œ API์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ API Reference ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์„ค๊ณ„ ์„ธ๋ถ€ ์‚ฌํ•ญ์„ ํŒŒ๊ธฐ ์ „์— ๋‹ค์Œ ์„น์…˜์„ ๋งˆ๋ฌด๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

์ฝ”๋“œ ๊ตฌ์„ฑ

์ด ์‹œ์ ์—์„œ ๊ฐ€์ ธ์˜จ ํ•จ์ˆ˜๋กœ ์ปดํฌ๋„ŒํŠธ API๋ฅผ ๋ณต์ œํ–ˆ์Šต๋‹ˆ๋‹ค. ์˜ต์…˜์œผ๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ •์˜ํ•˜๋Š” ๊ฒƒ์€ ํฐ ๊ธฐ๋Šฅ์œผ๋กœ ๋ชจ๋“  ๊ฒƒ์„ ํ•จ๊ป˜ ํ˜ผํ•ฉํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ํ›จ์”ฌ ๋” ์ฒด๊ณ„์ ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค!

์ดํ•ดํ•  ์ˆ˜ ์žˆ๋Š” ์ฒซ์ธ์ƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋™๊ธฐ ๋ถ€์—ฌ ์„น์…˜์—์„œ ์–ธ๊ธ‰ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ Composition API๋Š” ์‹ค์ œ๋กœ ๋ณต์žกํ•œ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ณด๋‹ค ์ฒด๊ณ„์ ์ธ ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑ ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์šฐ๋ฆฌ๋Š” ์ด์œ ๋ฅผ ์„ค๋ช…ํ•˜๋ ค๊ณ  ๋…ธ๋ ฅํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

"์กฐ์งํ™”๋œ ์ฝ”๋“œ"๋ž€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

ํ•œ ๊ฑธ์Œ ๋ฌผ๋Ÿฌ์„œ์„œ "์กฐ์งํ™”๋œ ์ฝ”๋“œ"์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐ ํ•  ๋•Œ ์‹ค์ œ๋กœ ๋ฌด์—‡์„ ์˜๋ฏธํ•˜๋Š” ์ง€ ์ƒ๊ฐํ•ด ๋ด…์‹œ๋‹ค. ์ฝ”๋“œ๋ฅผ ์ฒด๊ณ„์ ์œผ๋กœ ์œ ์ง€ํ•˜๋Š” ์ตœ์ข… ๋ชฉํ‘œ๋Š” ์ฝ”๋“œ๋ฅผ ๋ณด๋‹ค ์‰ฝ๊ฒŒ ์ฝ๊ณ  ์ดํ•ดํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ฝ”๋“œ๋ฅผ "์ดํ•ด"ํ•œ๋‹ค๋Š” ๊ฒƒ์€ ๋ฌด์—‡์„ ์˜๋ฏธํ•ฉ๋‹ˆ๊นŒ? ์ปดํฌ๋„ŒํŠธ์— ํฌํ•จ๋œ ์˜ต์…˜์„ ์•Œ๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ปดํฌ๋„ŒํŠธ๋ฅผ "์ดํ•ด"ํ•œ๋‹ค๊ณ  ์‹ค์ œ๋กœ ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ž‘์„ฑํ•œ ํฐ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณธ ์ ์ด ์žˆ์Šต๋‹ˆ๊นŒ? (์˜ˆ๋ฅผ ๋“ค์–ด ์ด๊ฒƒ) ๊ทธ๋ฆฌ๊ณ  ๋จธ๋ฆฌ๋ฅผ ๊ฐ์‹ธ๋งค๊ณ  ํž˜๋“  ์‹œ๊ฐ„์„ ๋ณด๋‚ด๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

์œ„์˜ ๋งํฌ์™€ ๊ฐ™์€ ํฐ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ†ตํ•ด ๋™๋ฃŒ ๊ฐœ๋ฐœ์ž๋ฅผ ์–ด๋–ป๊ฒŒ ๋„์šธ ์ˆ˜ ์žˆ์„์ง€ ์ƒ๊ฐํ•ด๋ณด์‹ญ์‹œ์˜ค. "์ด ์ปดํฌ๋„ŒํŠธ๋Š” ์ด๋Ÿฌํ•œ ๋ฐ์ดํ„ฐ ์†์„ฑ, ๊ณ„์‚ฐ๋œ ์†์„ฑ ๋ฐ ๋ฐฉ๋ฒ•์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค" ๋Œ€์‹  "์ด ์ปดํฌ๋„ŒํŠธ๋Š” X, Y ๋ฐ Z๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค"๋กœ ์‹œ์ž‘ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ดํ•ดํ•˜๋Š” ๋ฐ ์žˆ์–ด "์ปดํฌ๋„ŒํŠธ๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ์˜ต์…˜"๋ณด๋‹ค๋Š” "์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ˆ˜ํ–‰ํ•˜๋ ค๋Š” ์ž‘์—…" (์ฆ‰, ์ฝ”๋“œ์˜ ์˜๋„)์— ๋” ๊ด€์‹ฌ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ต์…˜ ๊ธฐ๋ฐ˜ API๋กœ ์ž‘์„ฑ๋œ ์ฝ”๋“œ๋Š” ํ›„์ž์— ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์‘๋‹ตํ•˜์ง€๋งŒ ์ „์ž๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ๋ฐ ๋‹ค์†Œ ์—ด์•…ํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

๋…ผ๋ฆฌ์  ๋ฌธ์ œ vs. ์˜ต์…˜ ํƒ€์ž…

์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ฒ˜๋ฆฌํ•˜๋Š” "๋…ผ๋ฆฌ์  ๋ฌธ์ œ"๋กœ "X, Y ๋ฐ Z"๋ฅผ ์ •์˜ํ•ด ๋ด…์‹œ๋‹ค. ์ „์ฒด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ•˜๋‚˜์˜ ๋…ผ๋ฆฌ์  ๋ฌธ์ œ๋ฅผ ๋‹ค๋ฃจ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ€๋…์„ฑ ๋ฌธ์ œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์ž‘์€ ๋‹จ์ผ ๋ชฉ์  ์ปดํฌ๋„ŒํŠธ์—๋Š” ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ณ ๊ธ‰ ์‚ฌ์šฉ ์‚ฌ๋ก€์—์„œ๋Š” ์ด ๋ฌธ์ œ๊ฐ€ ํ›จ์”ฌ ๋‘๋“œ๋Ÿฌ์ง‘๋‹ˆ๋‹ค. ์˜ˆ๋กœ์„œ Vue CLI UI file explorer ๋ฅผ ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค. ์ปดํฌ๋„ŒํŠธ๋Š” ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋…ผ๋ฆฌ์  ๋ฌธ์ œ๋ฅผ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • ํ˜„์žฌ ํด๋” ์ƒํƒœ ์ถ”์  ๋ฐ ๋‚ด์šฉ ํ‘œ์‹œ
  • ํด๋” ํƒ์ƒ‰ ์ฒ˜๋ฆฌ (์—ด๊ธฐ, ๋‹ซ๊ธฐ, ์ƒˆ๋กœ ๊ณ ์นจ)
  • ์ƒˆ ํด๋” ์ƒ์„ฑ ์ฒ˜๋ฆฌ
  • ์ฆ๊ฒจ ์ฐพ๊ธฐ ํด๋”๋งŒ ํ‘œ์‹œ ์ „ํ™˜
  • ์ˆจ๊น€ ํด๋” ํ‘œ์‹œ ์ „ํ™˜
  • ํ˜„์žฌ ์ž‘์—… ๋””๋ ‰ํ† ๋ฆฌ ๋ณ€๊ฒฝ ์ฒ˜๋ฆฌ

์˜ต์…˜ ๊ธฐ๋ฐ˜ ์ฝ”๋“œ๋ฅผ ์ฝ์Œ์œผ๋กœ์จ ์ด๋Ÿฌํ•œ ๋…ผ๋ฆฌ์  ๋ฌธ์ œ๋ฅผ ์ฆ‰์‹œ ์ธ์‹ํ•˜๊ณ  ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ํ™•์‹คํžˆ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ํŠน์ • ๋…ผ๋ฆฌ์  ๋ฌธ์ œ์™€ ๊ด€๋ จ๋œ ์ฝ”๋“œ๊ฐ€ ์ข…์ข… ์กฐ๊ฐ ๋‚˜๊ณ  ํฉ์–ด์ ธ ์žˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด "์ƒˆ ํด๋” ๋งŒ๋“ค๊ธฐ" ๊ธฐ๋Šฅ์€ ๋‘ ๋ฐ์ดํ„ฐ ์†์„ฑ, ํ•˜๋‚˜์˜ ๊ณ„์‚ฐ๋œ ์†์„ฑ ๋ฐ ๋ฉ”์†Œ๋“œ - ๋ฉ”์†Œ๋“œ๋Š” ๋ฐ์ดํ„ฐ ์†์„ฑ์—์„œ 100 ์ค„ ์ด์ƒ ๋–จ์–ด์ง„ ์œ„์น˜์— ์ •์˜๋ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋…ผ๋ฆฌ์  ๋ฌธ์ œ๋ฅผ ๊ฐ๊ฐ ์ƒ‰์ƒ์œผ๋กœ ๊ตฌ๋ถ„ํ•˜๋ฉด ์ปดํฌ๋„ŒํŠธ ์˜ต์…˜์œผ๋กœ ํ‘œํ˜„ํ•  ๋•Œ ์กฐ๊ฐํ™”๊ฐ€ ์–ด๋–ป๊ฒŒ ๋ฐœ์ƒํ•˜๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

์ฐธ๊ณ : ์›๋ž˜ ์ฝ”๋“œ๋Š” ๋ช‡ ๊ตฐ๋ฐ ๊ฐœ์„  ๋  ์ˆ˜ ์žˆ์ง€๋งŒ ์‹ค์ œ๋กœ ์ž‘์„ฑํ•œ ์‹ค์ œ ์ฝ”๋“œ์˜ ์˜ˆ๋ฅผ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•ด ์ˆ˜์ •์—†์ด ์ตœ์‹  ์ปค๋ฐ‹์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค(์ด ๊ธ€์„ ์“ฐ๋Š” ์‹œ์ ์—์„œ).

๋™์ผํ•œ ๋…ผ๋ฆฌ์  ๋ฌธ์ œ์™€ ๊ด€๋ จ๋œ ์ฝ”๋“œ๋ฅผ ํ•จ๊ป˜ ๋ฐฐ์น˜ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ํ›จ์”ฌ ๋” ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋ฐ”๋กœ Composition API๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋Š” ์ผ์ž…๋‹ˆ๋‹ค. "์ƒˆ ํด๋” ๋งŒ๋“ค๊ธฐ" ๊ธฐ๋Šฅ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function useCreateFolder (openFolder) {
  // ์›๋ž˜ ๋ฐ์ดํ„ฐ ์†์„ฑ
  const showNewFolder = ref(false)
  const newFolderName = ref('')

  // ์›๋ž˜ ๊ณ„์‚ฐ๋œ ์†์„ฑ
  const newFolderValid = computed(() => isValidMultiName(newFolderName.value))

  // ์›๋ž˜ ๋ฉ”์†Œ๋“œ
  async function createFolder () {
    if (!newFolderValid.value) return
    const result = await mutate({
      mutation: FOLDER_CREATE,
      variables: {
        name: newFolderName.value
      }
    })
    openFolder(result.data.folderCreate.path)
    newFolderName.value = ''
    showNewFolder.value = false
  }

  return {
    showNewFolder,
    newFolderName,
    newFolderValid,
    createFolder
  }
}

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

์ด ๋น„๊ต์—๋Š” import ๋ฌธ๊ณผ setup() ํ•จ์ˆ˜๋Š” ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. Composition API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์‹œ ๊ตฌํ˜„ ๋œ ์ „์ฒด ์ปดํฌ๋„ŒํŠธ๋Š” ์—ฌ๊ธฐ์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ ๋…ผ๋ฆฌ์  ๋ฌธ์ œ์— ๋Œ€ํ•œ ์ฝ”๋“œ๋Š” ์ด์ œ ์ปดํฌ์ง€์…˜ ํ•จ์ˆ˜๋กœ ํ•จ๊ป˜ ๋ฐฐ์น˜๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํฐ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‹ค๋ฃฐ ๋•Œ ์ผ์ •ํ•œ "์ ํ”„"๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ปดํฌ์ง€์…˜ ํ•จ์ˆ˜๋ฅผ ํŽธ์ง‘๊ธฐ์—์„œ ์ ‘์–ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ›จ์”ฌ ์‰ฝ๊ฒŒ ์Šค์บ”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

export default {
  setup() { // ...
  }
}

function useCurrentFolderData(networkState) { // ...
}

function useFolderNavigation({ networkState, currentFolderData }) { // ...
}

function useFavoriteFolder(currentFolderData) { // ...
}

function useHiddenFolders() { // ...
}

function useCreateFolder(openFolder) { // ...
}

setup() ํ•จ์ˆ˜๋Š” ์ด์ œ ๋ชจ๋“  ์ปดํฌ์ง€์…˜ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ์ง„์ž…์  ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

export default {
  setup () {
    // Network
    const { networkState } = useNetworkState()

    // Folder
    const { folders, currentFolderData } = useCurrentFolderData(networkState)
    const folderNavigation = useFolderNavigation({ networkState, currentFolderData })
    const { favoriteFolders, toggleFavorite } = useFavoriteFolders(currentFolderData)
    const { showHiddenFolders } = useHiddenFolders()
    const createFolder = useCreateFolder(folderNavigation.openFolder)

    // Current working directory
    resetCwdOnLeave()
    const { updateOnCwdChanged } = useCwdUtils()

    // Utils
    const { slicePath } = usePathUtils()

    return {
      networkState,
      folders,
      currentFolderData,
      folderNavigation,
      favoriteFolders,
      toggleFavorite,
      showHiddenFolders,
      createFolder,
      updateOnCwdChanged,
      slicePath
    }
  }
}

๋ฌผ๋ก , ์ด๊ฒƒ์€ ์˜ต์…˜ API๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์ž‘์„ฑํ•  ํ•„์š”๊ฐ€ ์—†๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ setup() ํ•จ์ˆ˜๊ฐ€ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฌด์—‡์„ ํ•˜๋ ค๊ณ  ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ๊ตฌ๋‘ ์„ค๋ช…๊ณผ ๊ฑฐ์˜ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์ฝ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์˜ต์…˜ ๊ธฐ๋ฐ˜ ๋ฒ„์ „์—์„œ ์™„์ „ํžˆ ๋ˆ„๋ฝ๋œ ์ •๋ณด์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ ์ „๋‹ฌ๋˜๋Š” ์ธ์ˆ˜๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ปดํฌ์ง€์…˜ ํ•จ์ˆ˜๊ฐ„์˜ ์ข…์†์„ฑ ํ๋ฆ„์„ ๋ช…ํ™•ํ•˜๊ฒŒ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ ๋ฐ˜ํ™˜๋ฌธ์€ ํ…œํ”Œ๋ฆฟ์— ๋…ธ์ถœ๋œ ๋‚ด์šฉ์„ ํ™•์ธํ•˜๋Š” ๋‹จ์ผ ์žฅ์†Œ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

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

๋…ผ๋ฆฌ ์ถ”์ถœ ๋ฐ ์žฌ์‚ฌ์šฉ

Composition API๋Š” ์ปดํฌ๋„ŒํŠธ์—์„œ ๋กœ์ง์„ ์ถ”์ถœํ•˜๊ณ  ์žฌ์‚ฌ์šฉํ•  ๋•Œ ๋งค์šฐ ์œ ์—ฐํ•ฉ๋‹ˆ๋‹ค. ์ปดํฌ์ง€์…˜ ํ•จ์ˆ˜๋Š” ๋งˆ๋ฒ•์˜ this ์ปจํ…์ŠคํŠธ์— ์˜์กดํ•˜๋Š” ๋Œ€์‹  ์ธ์ˆ˜์™€ ์ „ ์„ธ๊ณ„์ ์œผ๋กœ ๊ฐ€์ ธ์˜จ Vue API์—๋งŒ ์˜์กดํ•ฉ๋‹ˆ๋‹ค. ๋‹จ์ˆœํžˆ ์ปดํฌ๋„ŒํŠธ ๋กœ์ง์„ ํ•จ์ˆ˜๋กœ ๋‚ด๋ณด๋‚ด์„œ ์ปดํฌ๋„ŒํŠธ ๋กœ์ง์˜ ์ผ๋ถ€๋ฅผ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ์˜ ์ „์ฒด setup ํ•จ์ˆ˜๋ฅผ ๋‚ด๋ณด๋‚ด์„œ extends ์™€ ๋™์ผํ•œ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ์‚ดํŽด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค: ๋งˆ์šฐ์Šค ์œ„์น˜ ์ถ”์ .

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

export function useMousePosition() {
  const x = ref(0)
  const y = ref(0)

  function update(e) {
    x.value = e.pageX
    y.value = e.pageY
  }

  onMounted(() => {
    window.addEventListener('mousemove', update)
  })

  onUnmounted(() => {
    window.removeEventListener('mousemove', update)
  })

  return { x, y }
}

๋‹ค์Œ์€ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

import { useMousePosition } from './mouse'

export default {
  setup() {
    const { x, y } = useMousePosition()
    // other logic...
    return { x, y }
  }
}

ํŒŒ์ผ ํƒ์ƒ‰๊ธฐ ์˜ˆ์ œ์˜ Composition API ๋ฒ„์ „์—์„œ๋Š” ์ผ๋ถ€ ์œ ํ‹ธ๋ฆฌํ‹ฐ ์ฝ”๋“œ(์˜ˆ: usePathUtils ๋ฐ useCwdUtils)๋ฅผ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์— ์œ ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์™ธ๋ถ€ ํŒŒ์ผ๋กœ ์ถ”์ถœํ–ˆ์Šต๋‹ˆ๋‹ค.

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

  • ๋ Œ๋”๋ง ์ปจํ…์ŠคํŠธ์— ๋…ธ์ถœ๋œ ์†์„ฑ์˜ ์†Œ์Šค๊ฐ€ ๋ช…ํ™•ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์—ฌ๋Ÿฌ ๋ฏน์Šค์ธ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ปดํฌ๋„ŒํŠธ์˜ ํ…œํ”Œ๋ฆฟ์„ ์ฝ์„ ๋•Œ ํŠน์ • ์†์„ฑ์„ ์ฃผ์ž…ํ•œ ๋ฏน์Šค์ธ์„ ๊ตฌ๋ถ„ํ•˜๊ธฐ๊ฐ€ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋„ค์ž„ ์ŠคํŽ˜์ด์Šค ์ถฉ๋Œ. ๋ฏน์Šค์ธ์€ ์†์„ฑ ๋ฐ ๋ฉ”์„œ๋“œ ์ด๋ฆ„๊ณผ ์ถฉ๋Œํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š” ๋ฐ˜๋ฉด HOC๋Š” prop ์ด๋ฆ„๊ณผ ์ถฉ๋Œ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์„ฑ๋Šฅ. HOC ๋ฐ ๋ Œ๋”๋ฆฌ์Šค ์ปดํฌ๋„ŒํŠธ์—๋Š” ์„ฑ๋Šฅ ๋น„์šฉ์ด ๋“œ๋Š” ์ถ”๊ฐ€ ์ƒํƒœ ์ €์žฅ ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

Composition API์™€ ๋น„๊ตํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ํ…œํ”Œ๋ฆฟ์— ๋…ธ์ถœ๋œ ์†์„ฑ์€ ์ปดํฌ์ง€์…˜ ํ•จ์ˆ˜์—์„œ ๋ฐ˜ํ™˜๋œ ๊ฐ’์ด๋ฏ€๋กœ ๋ช…ํ™•ํ•œ ์†Œ์Šค๋ฅผ ๊ฐ–์Šต๋‹ˆ๋‹ค.
  • ์ปดํฌ์ง€์…˜ ํ•จ์ˆ˜์—์„œ ๋ฐ˜ํ™˜๋œ ๊ฐ’์˜ ์ด๋ฆ„์„ ์ž„์˜๋กœ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋„ค์ž„ ์ŠคํŽ˜์ด์Šค ์ถฉ๋Œ์ด ์—†์Šต๋‹ˆ๋‹ค.
  • ๋กœ์ง ์žฌ์‚ฌ์šฉ์„ ์œ„ํ•ด ์ƒ์„ฑ๋œ ๋ถˆํ•„์š”ํ•œ ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

๊ธฐ์กด API์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ

Composition API๋Š” ๊ธฐ์กด ์˜ต์…˜ ๊ธฐ๋ฐ˜ API์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • Composition API๋Š” 2.x ์˜ต์…˜ (data, computed & methods) ์ด์ „์— ํ•ด๊ฒฐ๋˜์—ˆ์œผ๋ฉฐ ํ•ด๋‹น ์˜ต์…˜์œผ๋กœ ์ •์˜๋œ ์†์„ฑ์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  • setup() ์—์„œ ๋ฐ˜ํ™˜๋œ ์†์„ฑ์€ this์— ๋…ธ์ถœ๋˜๋ฉฐ 2.x ์˜ต์…˜ ๋‚ด์—์„œ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ”Œ๋Ÿฌ๊ทธ์ธ ๊ฐœ๋ฐœ

์˜ค๋Š˜๋‚  ๋งŽ์€ Vue ํ”Œ๋Ÿฌ๊ทธ์ธ์€ this ์— ์†์„ฑ์„ ์ฃผ์ž…ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด Vue Router๋Š” this.$route์™€ this.$router ๋ฅผ ์ฃผ์ž…ํ•˜๊ณ  Vuex๋Š” this.$store๋ฅผ ์ฃผ์ž…ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ ํ”Œ๋Ÿฌ๊ทธ์ธ์€ ์‚ฌ์šฉ์ž๊ฐ€ ์ฃผ์ž…๋œ ์†์„ฑ์— ๋Œ€ํ•œ Vue ํƒ€์ดํ•‘์„ ๊ฐ•ํ™”ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํƒ€์ž… ์ถ”๋ก ์ด ๊นŒ๋‹ค๋กœ์›Œ์กŒ์Šต๋‹ˆ๋‹ค.

Composition API๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” this ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋Œ€์‹  ํ”Œ๋Ÿฌ๊ทธ์ธ ๋‚ด๋ถ€์ ์œผ๋กœ provide์™€ inject ๋ฅผ ํ™œ์šฉํ•˜๊ณ  ์ปดํฌ์ง€์…˜ ํ•จ์ˆ˜๋ฅผ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ์€ ํ”Œ๋Ÿฌ๊ทธ์ธ์— ๋Œ€ํ•œ ๊ฐ€์ƒ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

const StoreSymbol = Symbol()

export function provideStore(store) {
  provide(StoreSymbol, store)
}

export function useStore() {
  const store = inject(StoreSymbol)
  if (!store) {
    // throw error, no store provided
  }
  return store
}

๊ทธ๋ฆฌ๊ณ  ์ฝ”๋“œ๋ฅผ ์†Œ๋น„ ํ•  ๋•Œ:

// provide store at component root
//
const App = {
  setup() {
    provideStore(store)
  }
}

const Child = {
  setup() {
    const store = useStore()
    // use the store
  }
}

Global API change RFC์— ์ œ์•ˆ๋œ ์•ฑ ๋ ˆ๋ฒจ ์ œ๊ณต์„ ํ†ตํ•ด ์Šคํ† ์–ด๋ฅผ ์ œ๊ณตํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์‚ฌ์šฉ์ธก ์ปดํฌ๋„ŒํŠธ์˜ useStore ์Šคํƒ€์ผ API๋Š” ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

๋ฌธ์ œ์ 

Refs ๋„์ž…์˜ ์˜ค๋ฒ„ํ—ค๋“œ

Ref๋Š” ๊ธฐ์ˆ ์ ์œผ๋กœ ์ด ์ œ์•ˆ์—์„œ ์†Œ๊ฐœ๋œ ์œ ์ผํ•œ ์ƒˆ๋กœ์šด ๊ฐœ๋…์ž…๋‹ˆ๋‹ค. this์— ๋Œ€ํ•œ ์—‘์„ธ์Šค์— ์˜์กดํ•˜์ง€ ์•Š๊ณ  ๋ฐ˜์‘๊ฐ’์„ ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด ๋„์ž…๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋‹จ์ ์€:

  1. ์ปดํฌ์ง€์…˜ API๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ, API์™€ ์ž‘์—… ํ•  ๋•Œ ์ •์‹ ์  ๋ถ€๋‹ด์„ ์ฆ๊ฐ€ ์‹œ์ผœ์„œ ์ฐธ์กฐ๊ฐ’๊ณผ ์ผ๋ฐ˜๊ฐ’ ๋ฐ ๊ฐ์ฒด๋ฅผ ์ง€์†์ ์œผ๋กœ ๊ตฌ๋ถ„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    ๋ช…๋ช… ๊ทœ์น™(์˜ˆ: ๋ชจ๋“  ์ฐธ์กฐ ๋ณ€์ˆ˜์˜ ์ ‘๋ฏธ์‚ฌ๋ฅผ xxxRef๋กœ ์‚ฌ์šฉ)์„ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ํƒ€์ž… ์‹œ์Šคํ…œ์„ ์‚ฌ์šฉํ•˜๋ฉด ์ •์‹ ์  ๋ถ€๋‹ด์„ ํฌ๊ฒŒ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด์—, ์ฝ”๋“œ ๊ตฌ์„ฑ์˜ ์œ ์—ฐ์„ฑ์ด ํ–ฅ์ƒ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ปดํฌ๋„ŒํŠธ ๋กœ์ง์ด ๋กœ์ปฌ ์ปจํ…์ŠคํŠธ๊ฐ€ ๋‹จ์ˆœํ•˜๊ณ  refs์˜ ์˜ค๋ฒ„ํ—ค๋“œ๋ฅผ ์‰ฝ๊ฒŒ ๊ด€๋ฆฌ ํ•  ์ˆ˜ ์žˆ๋Š” ์ž‘์€ ๊ธฐ๋Šฅ์œผ๋กœ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋” ๋งŽ์Šต๋‹ˆ๋‹ค.
  2. refs๋ฅผ ์ฝ๊ณ  ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์€ .value๊ฐ€ ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ผ๋ฐ˜๊ฐ’์œผ๋กœ ์ž‘์—…ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๋” ์žฅํ™ฉํ•ฉ๋‹ˆ๋‹ค.

    ์ผ๋ถ€๋Š” ์ด๊ฒƒ์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์ปดํŒŒ์ผ ํƒ€์ž„ ์‹ ํ…์Šค ์Šˆ๊ฑฐ(Svelte 3์™€ ์œ ์‚ฌ)์„ ์ œ์•ˆํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ์ˆ ์ ์œผ๋กœ ์‹คํ˜„ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ Vue์˜ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์˜๋ฏธ๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(Svelte์™€ ๋น„๊ต์—์„œ ๋…ผ์˜ ๋จ). ์ฆ‰, ์ด๊ฒƒ์€ Userland์—์„œ Babel ํ”Œ๋Ÿฌ๊ทธ์ธ์œผ๋กœ ๊ธฐ์ˆ ์ ์œผ๋กœ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” Ref ๊ฐœ๋…์„ ์™„์ „ํžˆ ํ”ผํ•˜๊ณ  ๋ฐ˜์‘์„ฑ ๊ฐ์ฒด๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€์— ๋Œ€ํ•ด ๋…ผ์˜ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜:

  • ๊ณ„์‚ฐ๋œ ๊ฒŒํ„ฐ๋Š” ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ ํƒ€์ž…์„ ๋ฐ˜ํ™˜ ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ Ref์™€ ์œ ์‚ฌํ•œ ์ปจํ…Œ์ด๋„ˆ๋Š” ํ”ผํ• ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  • ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ ํƒ€์ž…๋งŒ ์˜ˆ์ƒํ•˜๊ฑฐ๋‚˜ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ปดํฌ์ง€์…˜ ํ•จ์ˆ˜๋Š” ๋ฐ˜์‘์„ฑ์„ ์œ„ํ•ด ๊ฐ์ฒด์˜ ๊ฐ’์„ ๋žฉํ•‘ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ์ œ๊ณตํ•˜๋Š” ํ‘œ์ค€ ๊ตฌํ˜„์ด ์—†๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉ์ž๋Š” ์ž์‹ ๋งŒ์˜ Ref์™€ ์œ ์‚ฌํ•œ ํŒจํ„ด(๊ทธ๋ฆฌ๊ณ  ์—์ฝ”์‹œ์Šคํ…œ ํŒŒํŽธํ™”)์„ ๊ฐœ๋ฐœํ•˜๊ฒŒ ๋  ๊ฐ€๋Šฅ์„ฑ์ด ํฝ๋‹ˆ๋‹ค.

Ref vs. Reactive

๋‹น์—ฐํžˆ, ์‚ฌ์šฉ์ž๋Š” refs๊ณผ reactive ์‚ฌ์ด์—์„œ ์–ด๋Š ๊ฒƒ์„ ์‚ฌ์šฉํ•ด์•ผ ํ• ์ง€ ํ˜ผ๋™ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•Œ์•„์•ผ ํ•  ์ฒซ ๋ฒˆ์งธ ์‚ฌํ•ญ์€ Composition API๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๋‘ ๊ฐ€์ง€๋ฅผ ๋ชจ๋‘ ์ดํ•ดํ•ด์•ผํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ•˜๋‚˜๋ฅผ ๋…์ ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋ฉด ๋‚œํ•ดํ•œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด๋‚˜ ๋ฐ”ํ€ด์˜ ์žฌ๋ฐœ๋ช… ๋  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค.

refs์™€ reactive์˜ ์ฐจ์ด์ ์€ ํ‘œ์ค€ JavaScript ๋กœ์ง์„ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ๋‹ค์†Œ ๋น„๊ต ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// ์ฒซ๋ฒˆ์งธ ์Šคํƒ€์ผ: ๋ณ„๋„์˜ ๋ณ€์ˆ˜
let x = 0
let y = 0

function updatePosition(e) {
  x = e.pageX
  y = e.pageY
}

// --- ๋น„๊ตํ•ด์„œ ---

// ๋‘๋ฒˆ์งธ ์Šคํƒ€์ผ: ๋‹จ์ผ ๊ฐ์ฒด
const pos = {
  x: 0,
  y: 0
}

function updatePosition(e) {
  pos.x = e.pageX
  pos.y = e.pageY
}
  • ref๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด, ์šฐ๋ฆฌ๋Š” ์ฒซ๋ฒˆ์งธ ์Šคํƒ€์ผ์„ refs๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ณด๋‹ค ๊ธฐ๋ณธ์ ์œผ๋กœ ๋™๋“ฑํ•œ ํ‘œํ˜„์œผ๋กœ ๋ณ€ํ™˜ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค(์›์‹œ๊ฐ’์„ ๋ฐ˜์‘์ ์œผ๋กœ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด).
  • ๋ฐ˜์‘์„ฑ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋‘๋ฒˆ์งธ ์Šคํƒ€์ผ๊ณผ ๊ฑฐ์˜ ๋™์ผํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” reactive๋กœ๋งŒ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

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

// ์ปดํฌ์ง€์…˜ ํ•จ์ˆ˜
function useMousePosition() {
  const pos = reactive({
    x: 0,
    y: 0
  })

  // ...
  return pos
}

// ์‚ฌ์šฉ์ธก ์ปดํฌ๋„ŒํŠธ
export default {
  setup() {
    // ๋ฐ˜์‘์„ฑ ์†์‹ค๋จ!
    const { x, y } = useMousePosition()
    return {
      x,
      y
    }

    // ๋ฐ˜์‘์„ฑ ์†์‹ค๋จ!
    return {
      ...useMousePosition()
    }

    // ์ด๊ฒƒ์ด ๋ฐ˜์‘์„ฑ์„ ์œ ์ง€ํ•˜๋Š” ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.
    // pos๋ฅผ ์žˆ๋Š” ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•˜๊ณ  x์™€ y๋ฅผ pos.x์™€ pos.y๋กœ ํƒฌํ”Œ๋ฆฟ์—์„œ ์ฐธ์กฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    return {
      pos: useMousePosition()
    }
  }
}

์ด ์ œ์•ฝ ์กฐ๊ฑด์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด toRefs API๊ฐ€ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค. ๋ฐ˜์‘ํ˜• ๊ฐ์ฒด์˜ ๊ฐ ์†์„ฑ์„ ํ•ด๋‹น ์ฐธ์กฐ๋กœ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

function useMousePosition() {
  const pos = reactive({
    x: 0,
    y: 0
  })

  // ...
  return toRefs(pos)
}

// x & y are now refs!
const { x, y } = useMousePosition()

์š”์•ฝํ•˜๋ฉด ๋‘ ๊ฐ€์ง€ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ์Šคํƒ€์ผ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  1. ์ผ๋ฐ˜์ ์ธ JavaScript์—์„œ ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ ํƒ€์ž… ๋ณ€์ˆ˜์™€ ๊ฐ์ฒด ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•˜๋Š” ๋ฐฉ์‹๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ref์™€ reactive๋ฅผ ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค. ์ด ์Šคํƒ€์ผ์„ ์‚ฌ์šฉํ•  ๋•Œ๋Š” IDE๋ฅผ ์ง€์›ํ•˜๋Š” ํƒ€์ž… ์‹œ์Šคํ…œ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.
  2. ๊ฐ€๋Šฅํ•˜๋ฉด reactive๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์ปดํฌ์ง€์…˜ ํ•จ์ˆ˜์—์„œ ๋ฐ˜์‘ํ˜• ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•  ๋•Œ toRefs๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด refs์˜ ์ •์‹ ์ ์ธ ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ์ค„์–ด๋“ค์ง€๋งŒ ๊ฐœ๋…์— ์ต์ˆ™ํ•ด์งˆ ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค.

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

๋ฐ˜ํ™˜๋ฌธ์˜ ์ •ํ™•์„ฑ

์ผ๋ถ€ ์‚ฌ์šฉ์ž๋“ค์€ setup() ์˜ ๋ฐ˜ํ™˜๋ฌธ์ด ์žฅํ™ฉํ•˜๊ณ  ๋ณด์ผ๋Ÿฟ ํ”Œ๋ ˆ์ดํŠธ์™€ ๊ฐ™์€ ๋Š๋‚Œ์„ ์ฃผ๋Š” ๊ฒƒ ์•„๋‹ˆ๋ƒ๋Š” ์šฐ๋ ค๋ฅผ ์ œ๊ธฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

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

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

  • setup() ์— ์„ ์–ธ๋œ ๋ณ€์ˆ˜๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ฐ˜ํ™˜๋ฌธ์„ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜๋Š” IDE ์ต์Šคํ…์…˜
  • ์•”์‹œ์ ์œผ๋กœ ๋ฐ˜ํ™˜๋ฌธ์„ ์ƒ์„ฑํ•˜๊ณ  ์‚ฝ์ž…ํ•˜๋Š” Babel ํ”Œ๋Ÿฌ๊ทธ์ธ

์œ ์—ฐ์„ฑ์ด ๋†’์„์ˆ˜๋ก ๋” ๋งŽ์€ ํ›ˆ๋ จ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค

๋งŽ์€ ์‚ฌ์šฉ์ž๋“ค์€ Composition API๊ฐ€ ์ฝ”๋“œ ๊ตฌ์„ฑ์— ๋” ๋งŽ์€ ์œ ์—ฐ์„ฑ์„ ์ œ๊ณตํ•˜์ง€๋งŒ ๊ฐœ๋ฐœ์ž๊ฐ€ "์˜ฌ๋ฐ”๋กœ" ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐ ๋” ๋งŽ์€ ํ›ˆ๋ จ์ด ํ•„์š”ํ•˜๋‹ค๊ณ  ์ง€์ ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ผ๋ถ€๋Š” API๊ฐ€ ๋ฏธ์ˆ™ํ•œ ์†์— ์ŠคํŒŒ๊ฒŒํ‹ฐ ์ฝ”๋“œ๋กœ ์ด์–ด์งˆ๊นŒ ๊ฑฑ์ •ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, Composition API๋Š” ์ฝ”๋“œ ํ’ˆ์งˆ์˜ ์ƒํ•œ์„ ์„ ๋†’์ด๋Š” ๋™์‹œ์— ํ•˜ํ•œ์„ ์„ ๋‚ฎ์ถ”๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ์–ด๋Š ์ •๋„ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ๋Š” ๋‹ค์Œ์„ ๋ฏฟ์Šต๋‹ˆ๋‹ค:

  1. ์ƒํ•œ์„ ์˜ ์ด๋“์ด ํ•˜ํ•œ์„ ์˜ ์†์‹ค๋ณด๋‹ค ํฝ๋‹ˆ๋‹ค.
  2. ์ ์ ˆํ•œ ๋ฌธ์„œ ๋ฐ ์ปค๋ฎค๋‹ˆํ‹ฐ ์ง€์นจ์„ ํ†ตํ•ด ์ฝ”๋“œ ๊ตฌ์„ฑ ๋ฌธ์ œ๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ผ๋ถ€ ์‚ฌ์šฉ์ž๋Š” Angular 1 ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„ค๊ณ„์—์„œ ์ฝ”๋“œ ์ž‘์„ฑ์ด ์ž˜๋ชป๋˜๋Š” ๋ฐฉ๋ฒ•์„ ์˜ˆ๋กœ ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. Composition API์™€ Angular 1 ์ปจํŠธ๋กค๋Ÿฌ์˜ ๊ฐ€์žฅ ํฐ ์ฐจ์ด์ ์€ ๊ณต์œ  ๋ฒ”์œ„ ์ปจํ…์ŠคํŠธ์— ์˜์กดํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ JavaScript ์ฝ”๋“œ ๊ตฌ์„ฑ์˜ ํ•ต์‹ฌ ๋งค์ปค๋‹ˆ์ฆ˜์ธ ๋…ผ๋ฆฌ๋ฅผ ๋ณ„๋„์˜ ํ•จ์ˆ˜๋กœ ํ›จ์”ฌ ์‰ฝ๊ฒŒ ๋ถ„๋ฆฌ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ชจ๋“  JavaScript ํ”„๋กœ๊ทธ๋žจ์€ ์—”ํŠธ๋ฆฌ ํŒŒ์ผ๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค(ํ”„๋กœ๊ทธ๋žจ์˜ ๊ฒฝ์šฐ setup() ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์‹ญ์‹œ์˜ค). ๋…ผ๋ฆฌ์ ์ธ ๊ด€์‹ฌ์‚ฌ์— ๋”ฐ๋ผ ํ”„๋กœ๊ทธ๋žจ์„ ๊ธฐ๋Šฅ๊ณผ ๋ชจ๋“ˆ๋กœ ๋ถ„ํ• ํ•˜์—ฌ ํ”„๋กœ๊ทธ๋žจ์„ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค. Composition API๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด Vue ์ปดํฌ๋„ŒํŠธ ์ฝ”๋“œ์— ๋Œ€ํ•ด์„œ๋„ ๋™์ผํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋งํ•ด, ์ž˜ ๊ตฌ์„ฑ๋œ JavaScript ์ฝ”๋“œ ์ž‘์„ฑ ๊ธฐ์ˆ ์€ Composition API๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์ž˜ ๊ตฌ์„ฑ๋œ Vue ์ฝ”๋“œ ์ž‘์„ฑ ๊ธฐ์ˆ ๋กœ ์ง์ ‘ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค.

์ ์šฉ ์ „๋žต

Composition API๋Š” ์ˆœ์ „ํžˆ ๋ถ€๊ฐ€์ ์ด๋ฉฐ ๊ธฐ์กด 2.x API์— ์˜ํ–ฅ์„ ๋ฏธ์น˜๊ฑฐ๋‚˜ ์–ด๋””์—๋„ ์‚ฌ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. @vue/composition ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ†ตํ•ด 2.x ํ”Œ๋Ÿฌ๊ทธ์ธ์œผ๋กœ ์ œ๊ณต๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์ฃผ์š” ๋ชฉํ‘œ๋Š” API๋ฅผ ์‹คํ—˜ํ•˜๊ณ  ํ”ผ๋“œ๋ฐฑ์„ ์ˆ˜์ง‘ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ˜„์žฌ ๊ตฌํ˜„์€ ์ด ์ œ์•ˆ์œผ๋กœ ์ตœ์‹  ์ƒํƒœ์ด์ง€๋งŒ ํ”Œ๋Ÿฌ๊ทธ์ธ์ด๋ผ๋Š” ๊ธฐ์ˆ ์  ์ œ์•ฝ์œผ๋กœ ์ธํ•ด ์•ฝ๊ฐ„์˜ ๋ถˆ์ผ์น˜๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ œ์•ˆ์ด ์—…๋ฐ์ดํŠธ ๋  ๋•Œ ๋ธŒ๋ ˆ์ดํฌ ์ฒด์ธ์ง€๊ฐ€ ๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ด ๋‹จ๊ณ„์—์„œ๋Š” ํ”„๋กœ๋•์…˜์—์„œ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” API๋ฅผ 3.0์— ๋‚ด์žฅํ•˜์—ฌ ์ œ๊ณตํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ์กด 2.x ์˜ต์…˜๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์•ฑ์—์„œ Composition API๋ฅผ ๋…์ ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ 2.x ์˜ต์…˜์—๋งŒ ์‚ฌ์šฉ๋˜๋Š” ์ฝ”๋“œ๋ฅผ ์‚ญ์ œํ•˜๊ณ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํฌ๊ธฐ๋ฅผ ์ค„์ด๊ธฐ ์œ„ํ•ด ์ปดํŒŒ์ผ ํƒ€์ž„ ํ”Œ๋ž˜๊ทธ๋ฅผ ์ œ๊ณต ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์€ ์™„์ „ํžˆ ์„ ํƒ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค.

API๋Š” ํ•ด๊ฒฐํ•ด์•ผ ํ•  ๋ฌธ์ œ๊ฐ€ ์ฃผ๋กœ ๋Œ€๊ทœ๋ชจ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์— ๋‚˜ํƒ€๋‚˜๊ธฐ ๋•Œ๋ฌธ์— ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ์œผ๋กœ ์ž๋ฆฌ๋ฅผ ์žก์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์„ค๋ช…์„œ๋ฅผ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์„ค๋ช…์„œ๋ฅผ ์ •๋ฐ€ ๊ฒ€์‚ฌํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. ๋Œ€์‹  ๋ฌธ์„œ์— ์ „์šฉ ์„น์…˜์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋ถ€๋ก

ํด๋ž˜์Šค API์˜ ํƒ€์ž… ์ด์Šˆ

ํด๋ž˜์Šค API๋ฅผ ๋„์ž…ํ•˜๋Š” ์ฃผ์š” ๋ชฉํ‘œ๋Š” ๋ณด๋‹ค ๋‚˜์€ TypeScript ์ถ”๋ก  ์ง€์›๊ณผ ํ•จ๊ป˜ ์ œ๊ณต๋˜๋Š” ๋Œ€์ฒด API๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ Vue ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์—ฌ๋Ÿฌ ์†Œ์Šค์—์„œ ์„ ์–ธ๋œ ์†์„ฑ์„ ๋‹จ์ผ this ์ปจํ…์ŠคํŠธ๋กœ ๋ณ‘ํ•ฉํ•ด์•ผํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์€ ํด๋ž˜์Šค ๊ธฐ๋ฐ˜ API์—์„œ๋„ ์•ฝ๊ฐ„์˜ ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚ต๋‹ˆ๋‹ค.

props ์ž…๋ ฅ์ด ๊ทธ ์˜ˆ์ž…๋‹ˆ๋‹ค. props์„ this ์— ๋ณ‘ํ•ฉํ•˜๋ ค๋ฉด ์ปดํฌ๋„ŒํŠธ ํด๋ž˜์Šค์— ์ œ๋„ค๋ฆญ ์ธ์ž๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ์€ ์ œ๋„ค๋ฆญ ์ธ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ์ž…๋‹ˆ๋‹ค.

interface Props {
  message: string
}

class App extends Component<Props> {
  static props = {
    message: String
  }
}

์ œ๋„ค๋ฆญ ์ธ์ž์— ์ „๋‹ฌ๋œ ์ธํ„ฐํŽ˜์ด์Šค๋Š” type-land์—๋งŒ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉ์ž๋Š” ์—ฌ์ „ํžˆ this ์— ๋Œ€ํ•œ props ํ”„๋ก์‹ฑ ๋™์ž‘์— ๋Œ€ํ•œ ๋Ÿฐํƒ€์ž„ props ์„ ์–ธ์„ ์ œ๊ณตํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ์ด ์ด์ค‘ ์„ ์–ธ์€ ์ค‘๋ณต๋˜๊ณ  ์–ด์ƒ‰ํ•ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ๋Œ€์•ˆ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ–ˆ์Šต๋‹ˆ๋‹ค.

class App extends Component<Props> {
  @prop message: string
}

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํŠนํžˆ TypeScript์˜ ํ˜„์žฌ ๊ตฌํ˜„์ด TC39 ์ œ์•ˆ๊ณผ ์™„์ „ํžˆ ์ผ์น˜ํ•˜์ง€ ์•Š์„ ๋•Œ ๋งŽ์€ ๋ถˆํ™•์‹ค์„ฑ๊ณผ ํ•จ๊ป˜ 2๋‹จ๊ณ„ ์‚ฌ์–‘์— ์˜์กดํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ this.$props ์—์„œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋กœ ์„ ์–ธ๋œ props ํƒ€์ž…์„ ๋…ธ์ถœ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์—†์œผ๋ฏ€๋กœ TSX ์ง€์›์ด ์ค‘๋‹ต๋ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๋Š” ๊ธฐ์ˆ ์ ์œผ๋กœ ์˜ˆ์ƒ๋Œ€๋กœ ์ž‘๋™ํ•˜์ง€ ์•Š์„ ๋•Œ @prop message: string = 'foo' ๋กœ prop์˜ ๊ธฐ๋ณธ๊ฐ’์„ ์„ ์–ธํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

React Hooks๊ณผ ๋น„๊ต

ํ•จ์ˆ˜ ๊ธฐ๋ฐ˜ API๋Š” React Hooks์™€ ๋™์ผํ•œ ์ˆ˜์ค€์˜ ๋…ผ๋ฆฌ ๊ตฌ์„ฑ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜์ง€๋งŒ ๋ช‡ ๊ฐ€์ง€ ์ค‘์š”ํ•œ ์ฐจ์ด์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. React Hooks์™€ ๋‹ฌ๋ฆฌ setup() ํ•จ์ˆ˜๋Š” ํ•œ๋ฒˆ๋งŒ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” Vue์˜ Composition API๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ์ผ๋ฐ˜์ ์œผ๋กœ ๊ด€์šฉ์  JavaScript ์ฝ”๋“œ์˜ ์ง๊ด€๊ณผ ๋” ์ž˜ ๋งž์Šต๋‹ˆ๋‹ค.
  • ํ˜ธ์ถœ ์ˆœ์„œ์— ๋ฏผ๊ฐํ•˜์ง€ ์•Š์œผ๋ฉฐ ์กฐ๊ฑด๋ถ€ ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๊ฐ ๋ Œ๋”์—์„œ ๋ฐ˜๋ณต์ ์œผ๋กœ ํ˜ธ์ถœ๋˜์ง€ ์•Š์œผ๋ฉฐ GC ์••๋ ฅ์ด ์ ์Šต๋‹ˆ๋‹ค.
  • ์ธ๋ผ์ธ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ณผ๋„ํ•˜๊ฒŒ ๋‹ค์‹œ ๋ Œ๋”๋งํ•˜๋Š” ๊ฒƒ์„ ๋ง‰๊ธฐ ์œ„ํ•ด useCallback ์ด ๊ฑฐ์˜ ํ•ญ์ƒ ํ•„์š”ํ•œ ๋ฌธ์ œ๋Š” ์•„๋‹™๋‹ˆ๋‹ค.
  • ์‚ฌ์šฉ์ž๊ฐ€ ์˜ฌ๋ฐ”๋ฅธ ์˜์กด์„ฑ ๋ฐฐ์—ด์„ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์„ ์žŠ์–ด ๋ฒ„๋ฆฐ ๊ฒฝ์šฐ useEffect ๋ฐ useMemo ๊ฐ€ ์˜ค๋ž˜๋œ ๋ณ€์ˆ˜๋ฅผ ์บก์ฒ˜ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ œ๋Š” ์•„๋‹™๋‹ˆ๋‹ค. Vue์˜ ์ž๋™ ์ข…์†์„ฑ ์ถ”์  ๊ธฐ๋Šฅ์€ ๊ฐ์‹œ์ž์™€ ๊ณ„์‚ฐ๋œ ๊ฐ’์ด ํ•ญ์ƒ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋ฌดํšจํ™”๋˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” React Hooks์˜ ์ฐฝ์˜์„ฑ์„ ์ธ์ •ํ•˜๋ฉฐ, ์ด ์ œ์•ˆ์˜ ์ฃผ์š” ์˜๊ฐ์›์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ๋ฌธ์ œ๋Š” ์„ค๊ณ„์— ์กด์žฌํ•˜๋ฉฐ Vue์˜ ๋ฐ˜์‘์„ฑ ๋ชจ๋ธ์ด ๊ทธ ์ฃผ์œ„์— ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•˜์Šต๋‹ˆ๋‹ค.

Svelte์™€ ๋น„๊ต

๋น„๋ก ๋งค์šฐ ๋‹ค๋ฅธ ๋…ธ์„ ์„ ์„ ํƒํ–ˆ์ง€๋งŒ, Composition API์™€ Svelte 3์˜ ์ปดํŒŒ์ผ๋Ÿฌ ๊ธฐ๋ฐ˜ ์ ‘๊ทผ ๋ฐฉ์‹์€ ์‹ค์ œ๋กœ ๊ฐœ๋…์ ์œผ๋กœ ์ƒ๋‹นํžˆ ๊ณตํ†ต์ ์ž…๋‹ˆ๋‹ค. ๋‹จ๊ณ„๋ณ„ ์˜ˆ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

Vue

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

export default {
  setup() {
    const count = ref(0)

    function increment() {
      count.value++
    }

    watchEffect(() => console.log(count.value))

    onMounted(() => console.log('mounted!'))

    return {
      count,
      increment
    }
  }
}
</script>

Svelte

<script>
import { onMount } from 'svelte'

let count = 0

function increment() {
  count++
}

$: console.log(count)

onMount(() => console.log('mounted!'))
</script>

Svelte ์ฝ”๋“œ๋Š” ์ปดํŒŒ์ผ ํƒ€์ž„์— ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋” ๊ฐ„๊ฒฐํ•ด ๋ณด์ž…๋‹ˆ๋‹ค.

  • ์ „์ฒด <script> ๋ธ”๋ก (import ๋ฌธ ์ œ์™ธ)์„ ํ•œ๋ฒˆ๋งŒ ์‹คํ–‰ํ•˜๋Š” ๋Œ€์‹  ๊ฐ ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค์— ๋Œ€ํ•ด ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜๋กœ ์•”์‹œ์ ์œผ๋กœ ๋ž˜ํ•‘ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ฐ€๋ณ€ ๋ฎคํ…Œ์ด์…˜์— ๋Œ€ํ•œ ๋ฐ˜์‘์„ฑ์„ ์•”์‹œ์ ์œผ๋กœ ๋“ฑ๋ก
  • ๋ชจ๋“  ๋ฒ”์œ„ ๋‚ด ๋ณ€์ˆ˜๋ฅผ ๋ Œ๋” ์ปจํ…์ŠคํŠธ์— ์•”์‹œ์ ์œผ๋กœ ๋…ธ์ถœ
  • $ ๋ฌธ์„ ์žฌ์‹คํ–‰๋œ ์ฝ”๋“œ๋กœ ์ปดํŒŒ์ผ

๊ธฐ์ˆ ์ ์œผ๋กœ Vue์—์„œ ๋™์ผํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค (userland Babel ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ํ†ตํ•ด ๊ฐ€๋Šฅ). ์šฐ๋ฆฌ๊ฐ€ ํ•˜์ง€ ์•Š๋Š” ์ฃผ๋œ ์ด์œ ๋Š” ํ‘œ์ค€ JavaScript์— ๋Œ€ํ•œ ์ง€์ง€ ์ž…๋‹ˆ๋‹ค. Vue ํŒŒ์ผ์˜ <script> ๋ธ”๋ก์—์„œ ์ฝ”๋“œ๋ฅผ ์ถ”์ถœํ•˜๋ฉด ํ‘œ์ค€ ES ๋ชจ๋“ˆ๊ณผ ๋™์ผํ•˜๊ฒŒ ์ž‘๋™ํ•˜๊ธฐ๋ฅผ ์›ํ•ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด Svelte <script> ๋ธ”๋ก ์•ˆ์˜ ์ฝ”๋“œ๋Š” ๊ธฐ์ˆ ์ ์œผ๋กœ ๋” ์ด์ƒ ํ‘œ์ค€ JavaScript๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ์ด ์ปดํŒŒ์ผ๋Ÿฌ ๊ธฐ๋ฐ˜ ์ ‘๊ทผ ๋ฐฉ์‹์—๋Š” ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋ฌธ์ œ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  1. ์ฝ”๋“œ๋Š” ์ปดํŒŒ์ผ๊ณผ ํ•จ๊ป˜ / ์ปดํŒŒ์ผ ์—†์ด ๋‹ค๋ฅด๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ํ”„๋กœ๊ทธ๋ ˆ์‹œ๋ธŒ ํ”„๋ ˆ์ž„์›Œํฌ๋กœ์„œ, ๋งŽ์€ Vue ์‚ฌ์šฉ์ž๋Š” ๋นŒ๋“œ ์„ค์ •์—†์ด ์‚ฌ์šฉํ•˜๊ธฐ๋ฅผ ์›ํ•˜๊ฑฐ๋‚˜ ํ•„์š”๋กœ ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ปดํŒŒ์ผ๋œ ๋ฒ„์ „์ด ๊ธฐ๋ณธ๊ฐ’์ด ๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด Svelte๋Š” ์ž์‹ ์„ ์ปดํŒŒ์ผ๋Ÿฌ๋กœ ์ง€์ •ํ•˜๊ณ  ๋นŒ๋“œ ๋‹จ๊ณ„์™€ ํ•จ๊ป˜๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋‘ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์˜์‹์ ์œผ๋กœ ๋งŒ๋“ค๋„ ์žˆ๋Š” ํŠธ๋ ˆ์ด๋“œ ์˜คํ”„์ž…๋‹ˆ๋‹ค.
  2. ์ฝ”๋“œ๋Š” ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€ / ์™ธ๋ถ€์—์„œ ๋‹ค๋ฅด๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. Svelte ์ปดํฌ๋„ŒํŠธ์—์„œ ํ‘œ์ค€ JavaScript ํŒŒ์ผ๋กœ ์กฐ์‹์„ ์ถ”์ถœํ•˜๋ ค๊ณ  ํ•  ๋•Œ, ์šฐ๋ฆฌ๋Š” ๋งˆ๋ฒ•์˜ ๊ฐ„๊ฒฐํ•œ ๊ตฌ๋ฌธ์„ ์ฝ๊ณ  ๋” ์ž์„ธํ•œ ์ €์ˆ˜์ค€ API ๋กœ ๋Œ์•„ ๊ฐ€์•ผํ•ฉ๋‹ˆ๋‹ค.
  3. Svelte์˜ ๋ฐ˜์‘ํ˜• ์ปดํŒŒ์ผ์€ ์ตœ์ƒ์œ„ ๋ณ€์ˆ˜์— ๋Œ€ํ•ด์„œ๋งŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ํ•จ์ˆ˜ ๋‚ด์— ์„ ์–ธ๋œ ๋ณ€์ˆ˜๋ฅผ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š์œผ๋ฏ€๋กœ ์ปดํฌ๋„ŒํŠธ ๋‚ด์— ์„ ์–ธ๋œ ํ•จ์ˆ˜์—์„œ ๋ฐ˜์‘ ์ƒํƒœ๋ฅผ ์บก์Šํ™” ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด ๊ธฐ๋Šฅ์€ ์ฝ”๋“œ ๊ตฌ์„ฑ์— ์‚ฌ์†Œํ•œ ์ œ์•ฝ ์กฐ๊ฑด์„ ๋ถ€์—ฌํ•ฉ๋‹ˆ๋‹ค. ์ด RFC์—์„œ ์„ค๋ช…ํ–ˆ๋“ฏ์ด ํฐ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์œ ์ง€ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.
  4. ๋น„ํ‘œ์ค€ ๋ฌธ๋ฒ•์€ TypeScript์™€์˜ ํ†ตํ•ฉ์— ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

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

โš ๏ธ **GitHub.com Fallback** โš ๏ธ