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개 이상 사용하는 순간 로직의 흐름을 따라가기가 어렵고, 실제 해당 datamethods가 어느 믹스인에 정의되어 있는지 파악하기가 어렵습니다. 이렇기 때문에 믹스인은 엄격한 규칙으로 사용 범위와 변수 명을 제한해야 합니다.

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-ifv-show의 차이점

서비스 개발할 때 많이 사용하는 v-if 디렉티브와 v-show 디렉티브의 차이점을 초기 렌더링 비용과 변경시 렌더링 비용으로 나누어 잘 비교하였습니다.

6. 목록 필터링 & 오더링 팁

특정 목록을 필터링 및 오더링 해야 할 때 computedmethods를 어떻게 구분해서 써야 하는 지 잘 기술되어 있습니다.

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에 대해서 본격적으로 파헤쳐 볼 다음 글들도 기대해 주세요. 긴 글 읽어 주셔서 감사드립니다 😄