이번 포스트에서는 SFC 기반에서 component의 정의와 사용에 대해 알아보자.
앞으로는 Vite 기반으로만 작성할 예정이기 때문에 이전 포스트에 대한 선행 학습이 반드시 필요하다.
https://goodteacher.tistory.com/545
컴퍼넌트 정의
Vite와 같은 빌드툴을 사용할 때 SFC(Single File Component) 기반에서 컴포넌트는 .vue 파일 하나당 하나의 컴포넌트를 작성한다.
따라서 재사용하고 싶은 내용을 하나의 .vue 파일에 <script>, <template>, <style>로 잘 구성해주면 된다. 이번에는 1초마다 카운트를 증가시키는 StopWatch라는 컴포넌트를 만들어보자.
기본적인 모습은 아래와 같다.
컴포넌트 작성
<script setup>
import { ref } from 'vue'
const count = ref(0)
let intervalId
const play = () => {
intervalId = setInterval(() => {
count.value++
}, 1000)
}
const stop = () => clearInterval(intervalId)
const reset = () => {
stop()
count.value = 0
}
</script>
<template>
<div>
<div>{{ count }}</div>
<button @click="play">P</button>
<button @click="stop">S</button>
<button @click="reset">R</button>
</div>
</template>
<style scoped>
div{
margin: 10px;
}
</style>
전반적으로 <template>, <script>, <style> 태그가 작성되어있고 내용은 기본적인 부분들이라 설명은 생략한다.
컴포넌트는 등록 방식에 따라 전역 컴포넌트와 지역 컴포넌트로 나뉜다. 등록 방식만 다를 뿐 작성 및 사용 방법은 동일하다. 먼저 전역 컴포넌트로 등록하고 사용하는 방법에 대해 알아보자.
전역 컴포넌트
전역 컴포넌트 등록
app.component() 메서드를 사용하여 현재 Vue 앱에 컴포넌트를 등록하여 어디서나 사용할 수 있게 한다. main.js를 아래와 같이 수정해보자.
// 1. 전역 컴포넌트 로딩
import StopWatch from './components/StopWatch.vue';
// 2. 전역 컴포넌트 등록
const app = createApp(App);
app.component("StopWatch", StopWatch)
app.mount('#app')
app.component의 첫 번째 파라미터로 넘겨준 "StopWatch"는 StopWatch.vue 컴포넌트를 참조하기 위한 이름이 된다.
전역 컴포넌트 사용
전역에 등록한 컴포넌트를 사용하기 위해 App.vue를 아래와 같이 단촐하게 수정해보자.
<script setup></script>
<template>
<h1>여기는 App.vue</h1>
<h2>전역 컴포넌트</h2>
<StopWatch/>
<StopWatch/>
</template>
<style scoped></style>
"StopWatch"라는 이름으로 컴포넌트를 등록하고 있지만 이녀석이 어디서왔는지에 대한 언급은 전혀 없는 상태이다. "전역" 레벨로 등록한 녀석이니 당연하다.
앱을 실행해보면 App 컴포넌트 안에 두 개의 StopWatch 컴포넌트가 잘 동작함을 알 수 있다. 개발자 도구를 이용해서 App을 검사해보면 이 구조를 좀 더 명확히 확인 할 수 있다.
각각의 StopWatch 컴포넌트들을 눌러보면 각각의 count를 가지고 있는데 컴포넌트들은 독립적으로 동작함을 알 수 있다.
컴포넌트 명명 규칙
Vue에서 컴포넌트를 등록할 때는 PascalCase와 KebabCase를 사용할 수 있다..
PascalCase를 사용하면 기존의 native html element와 구별이 가능하고 심지어 IDE에서 자동 완성도 가능하다. PascalCase로 작성된 태그는 <StopWatch/> 처럼 빈 태그로도 사용이 가능하다.
Kebab-case로도 작성할 수 있는데 이때는 <stop-watch></stop-watch> 처럼 사용 가능하고 빈 태그 형태로 사용할 수 없다.
권장 사항은 PascalCase이다.
<StopWatch></StopWatch>
<StopWatch/>
<stop-watch></stop-watch>
https://ko.vuejs.org/style-guide/rules-strongly-recommended.html#single-file-component-filename-casing
지역 컴포넌트
컴포넌트 작성
이번에는 지역 컴포넌트로 등록할 컴포넌트를 작성(GuguQuiz.vue)해보자.
<template>
<div>
<h1>구구단을 외자</h1>
<span>{{ num1 }} * {{ num2 }} = <input type="number" v-model="result" @change="solve" /></span>
</div>
</template>
<script setup>
import { ref} from 'vue'
const num1 = parseInt(Math.random() * 9 + 1)
const num2 = parseInt(Math.random() * 9 + 1)
const result = ref('0')
const solve = () => {
alert(result.value)
}
</script>
<style scoped>
h1 {
text-decoration: underline;
}
</style>
지역 컴포넌트 등록
지역 컴포넌트로 등록하려면 자식 컴포넌트를 사용하려는 컴포넌트 별로 등록해주면 된다. App.vue에서 다음과 같이 import를 통해 자식 컴포넌트를 등록해보자.
<script setup>
import GuguQuiz from "@/components/GuguQuiz.vue"
</script>
<template>
<h1>여기는 App.vue</h1>
<h2>전역 컴포넌트</h2>
<h2>지역 컴포넌트</h2>
<GuguQuiz></GuguQuiz>
<GuguQuiz/>
<gugu-quiz></gugu-quiz>
</template>
<style scoped>
</style>
등록 방법 이외에 사용법이나 명명법 자체는 전역으로 등록했을 때와 다를 바가 없다.
전역 등록 vs 로컬 등록
전역은 한번만 등록하면 모든 곳에서 다 활용이 가능하고 로컬은 활용 범위가 등록한 컴포넌트로 한정되기 때문에 얼핏 불편할것 같지만 의외로 전역은 단점이 많다.
- 전역 컴포넌트는 전역 변수와 같아서 한번 로딩되면 사용하지 않더라도 메모리에서 제거되지 않는다. 지역 컴포넌트는 부모 컴포넌트가 제거될 때 같이 제거된다.
- 전역 컴포넌트를 많이 사용하면 자식을 사용하는 부모 입장에서 자식의 구현을 찾기가 어렵기 때문에 유지보수가 힘들다. (내자식이 아니니까 ㅎ) 지역 컴포넌트 형태는 컴포넌트 별로 링크가 있어 쉽게 자식의 구현을 찾을 수 있다.
상황에 따라 다를 수 있지만 가급적 로컬 등록 방식을 사용하자.