Vue.js 코딩가이드 : Essential(Error Prevention)
늘 Vue를 사용하지만 코딩 스타일 가이드를 정독한 적은 없는 관계로.. 조금 시간이 난 김에 한번 스타일가이드를 정리해보려 합니다.
참고한 문서는 Vue.js Official Style Guide.
모든 가이드가 그렇듯, 절대적인 지표는 아니며 개발 방향을 정해주는 정도로 참고하면 되겠습니다.
Rule Categories
이하의 룰들은 총 4가지 카테고리로 나뉘게 된다.
명칭 | 우선순위 | 설명 |
---|---|---|
Priority A | Essential | - 에러를 방지한다. - 룰의 예외는 극히 드물다. |
Priority B | Strongly Recommended | - 코드의 가독성/개발 편의성을 높여준다. - 해당 룰을 지키지 않아도 코드는 실행될 수 있지만 가급적 룰을 따르는 것이 좋다. |
Priority C | Recommended | - 허용가능한/타당한 이유의 다른 방식이 있을때에는 꼭 따르지 않아도 된다. - 해당 룰에서는 가능한 다른 방법과 함께 default option을 제안한다. 개발자는 이들 중 자신의 프로젝트에 맞춰 따를 룰을 정할 수 있다. - 이러한 Community rule을 따르면 다른 코드를 이식해올 때 용이하다 |
Priority D | Use with caution | - 희귀한 edge case들을 처리하거나 legacy code의 migration을 위한 룰 - 남용시 코드 가독성을 떨어뜨리고 오류를 발생시킬 수 있다. |
Priority A Rules : Essential(Error Prevention)
Multi-word component names
컴포넌트명
은 반드시 여러개의 단어로 되어있어야 한다.(Root의 App 컴포넌트나, 같은 내장 컴포넌트 제외) 현재 존재하는, 앞으로 만들어질 수 있는 HTML 태그와의 혼선을 방지할 수 있다.(모든 HTML 태그는 single word)
Bad
1 | Vue.component('todo', { |
Good
1 | Vue.component('todo-item', { |
Component Data
- 컴포넌트의
data
는 반드시 함수형이어야 한다.(object 반환,new Vue
초기화시 제외) - 컴포넌트 data를 단순한 object형으로 선언할 경우 컴포넌트의 재사용성에 큰 문제 생긴다.
- 해당 컴포넌트를 사용하는 모든 instance에서 같은 data object를 참조한다.
- 즉, 컴포넌트의 데이터가 its own data가 아닌 shared data가 되어버린다. 어떤 하나가 행하는 deletion/adding/changing은 모든 다른 컴포넌트들에 영향을 미침.
- 따라서 각 컴포넌트는 자신만의 고유한 데이터를 가질 수 있어야하며, 컴포넌트의 data 필드를 특정 데이터 객체를 반환하는 함수형으로 선언함으로서 문제를 해결할 수 있다.
Bad
1 | Vue.component('some-comp', { |
Good
1 | Vue.component('some-comp', { |
Exception
1 | // It's OK to use an object directly in a root |
Prop definition
prop
은 가능한 한 상세하게 필드를 정의하는 것이 좋다.- 최소한 type은 명세해야 한다.
Bad
1 | // This is only OK when prototyping |
Good
1 | // Not bad |
Keyed v-for
- v-for 사용시에는 항상
key
가 있어야 한다. - v-for의 key는 내부 subtree의 제어에 사용된다.
- object consistancy를 유지하는 등의 예측가능한 행위를 제어/관리할 수 있도록 두는것이 좋다.
- 예를들어 리스트 아이템 [b,a]를 알파벳 순서로 정렬한다고 가정해보자.
- Vue는 가장 비용이 적게 드는 방식을 선택할 것. 가장 간단한 방법은 b를 삭제한 뒤 a 뒤에 다시 넣는 것이다.
- 하지만 만약 애니메이션 등을 사용해서 b를 삭제하면 안된다면? b가 텍스트필드라 정렬후에도 b에대한 focus를 잃어선 안된다면?
- 이때 b, a 각각에 고유한 키를 부여한다면 Vue가 보다 더 predictable 하게 행동하도록 제어할 수 있다.
Bad
1 | <ul> |
Good
1 | <ul> |
Avoid v-if with v-for
v-for과 v-if를 같은 element 내에서 사용하면 안된다.
- vue가 directive를 처리할떄
v-for
는v-if
보다 높은 우선순위를 갖는다. - 따라서 v-for와 v-if를 같이 사용한 아래와 같은 코드는
1
2
3
4
5<ul>
<li v-for="user in users" v-if="user.isActive" :key="user.id">
{{ user.name }}
</li>
</ul>다음과 같이 변환된다.
1
2
3
4
5this.users.map(function (user) {
if (user.isActive) {
return user.name
}
})따라서 user의 정보가 일부분만 바뀌어도 re-render를 위해 리스트 전체를 다시 iterate해야한다.
위와같은 경우
if조건을 v-for 컴포넌트의 상위 컴포넌트로 옮긴다
Computed 메서드에 user에 대한 필터링 조건을 설정하여 v-for로 iterate되는 리스트 자체를 필터링된 리스트로 사용한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<ul>
<li
v-for="user in activeUsers"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
...
computed: {
activeUsers: function () {
return this.users.filter(function (user) {
return user.isActive
})
}
}- vue가 directive를 처리할떄
Component style scoping
- Root의 App컴포넌트를 제외한 모든 컴포넌트의 스타일은 scoped 되어야 한다 :
- 혹은 고유한 클래스명을 사용하는 것도 방법일 수 있다.
Private property names
- private function이 외부에서 접근 불가능하도록 module scoping을 사용한다.
- 혹은 plugin, mixin 의 모든 custom private properties에 대해
$_
prefix를 사용한다._
prefix는 뷰 자체 private properties를 정의하는데에 사용하므로_update
와 같은 이름은 instance property를 overwrite할 위험이 있다.$
는 special instance properties를 지칭하는데 사용된다.- 따라서 두개의 prefix를 합친
$_yourPluginName
의 사용을 권장.
Bad
1 | var myGreatMixin = { |
Good
1 | var myGreatMixin = { |
Excellent
1 | // Even better! |