[Vue3] Vue 프로젝트의 기본 구조 및 핵심 컨셉(Reactivity)과 이를 위한 컴포넌트 설계
Reactivity
객체의 내용이 변화함에 따라
화면의 내용도 바껴져 나가는 시스템을 Reactivity 시스템이라 한다.
Vue3는 Proxy라는 API를 통해 화면을 변경하고 있다.
🍍 Proxy
객체를 모방(Mocking
)한 다음, 동작을 추가할 수 있다 (기본 동작을 재정의)
Vue2에서는 Reactivity 주입을 위해 내부적으로 속성마다Object.defineProperty API
를 호출했는데,
Vue의 data에 미리 정의되어 있지 않은 속성에 대해서는 Reactivity 주입이 되지 않는 한계점이 있었다. Vue3부터는 Reactivity 주입을 위해 내부적으로 Proxy를 호출하는데,
어떤 속성이 들어와도 모두 동일한 Proxy 동작으로 엮어낼 수 있다.
Vue Application Instance
해당 인스턴스를 만들어서 유효하게 다룰 수 있는 화면의 영역을 지정하고
어느 부분에 마운트(mount)해서 보여줄건지를 설정해야 한다.
✨ 인스턴스 안에서 사용할 수 있는 속성을 ‘컴포넌트 옵션 속성’(= 인스턴스 옵션속성, 옵션 API)라고 한다.
컴포넌트 통신방식
⚠️ 컴포넌트 기반으로 화면을 개발하면 재사용성 🏆이 증가한다.
⚠️ Vue Application Instance를 생성하면 해당 객체는 루트(Root) 컴포넌트가 된다.
이후의 등록하는 컴포넌트는 하위 컴포넌트에 위치하게 되며,
각각의 컴포넌트는 고유한 데이터 유효범위를 가지고, 각각 데이터를 관리한다.
이러한 컴포넌트(화면 영역) 간에 어떤 식으로 데이터를 주고받을지를 정의해놓았다.
🎯 데이터 추적을 용이하게 하기 위해
상위 컴포넌트에서 하위 컴포넌트로는 props
를 통해 아래로 데이터를 전달하고,
하위 컴포넌트에서 상위 컴포넌트로는 이벤트를 발생(Event emit)시켜 데이터 조작을 호출한다.
이런 식으로, 같은 컴포넌트 레벨 사이의 통신은 상위 컴포넌트를 통해 이벤트를 발생시키고, 이벤트에 의해 바뀐 상위 컴포넌트의 데이터를 props로 내려보내주어 통신한다.
프레젠터 컴포넌트와 컨테이너 컴포넌트
트리의 끝단에 위치한 컴포넌트(프레젠터 컴포넌트)들은 최대한 UI적으로 표현만 하고,
상위 컴포넌트(컨테이너 컴포넌트)에서 데이터를 조작했을 때, 로직이 깔끔해지면서 Vue의 반응성 🏆이 극대화된다.
또한, 데이터 추적이 쉽고, 꼬이지 않는다.
⚠️ 사실상 프레젠터 컴포넌트는 단지 이벤트를 발생시키거나 props로 데이터를 전달받는 역할을 한다.
🦇 UpperComponent.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<template>
<LowerComponent
:todoItems="todoItems"
@makeTodoEmpty="emptify"
></LowerComponent>
</template>
<script>
export default {
data() {
return {
todoItems: [
{
todo: "reorganizing"
},
{
todo: "writing"
}
]
};
},
methods: {
emptify(idx) {
this.todoItems.splice(idx, 1);
}
}
};
</script>
🦇 LowerComponent.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<ul>
<li v-for="(item, idx) in todoItems" @click="makeEmpty(idx)" :key="idx">
<!-- 생략 -->
</li>
</ul>
</template>
<script>
export default {
props: [todoItems]
methods: {
makeEmpty(idx) {
this.$emit('makeTodoEmpty', idx);
}
}
};
</script>
Vue의 템플릿 문법
- 🍍 Dom API
HTML tag
정보에 접근할 수 있는 기능
ex.document.querySelector('#app');
- 디렉티브
- v-로 시작하는 화면의 요소를 추가적인 자바스크립트 코드를 작성하지 않고
더 쉽게 조작하기 위한 Vue의 특별한 속성 (자주 사용되는 방식들을 모아 디렉티브 형태로 제공)- v-if / v-else
- v-for
- v-show * 조건이 맞지 않을 때 display: none 처리
- v-bind
:
* Vue에 선언된 데이터와 엮을 때
- v-on
@
* 이벤트(event) 제어
- v-model * input box의 데이터를 Vue의 data와 엮을 때
- ✨ class, id, style 바인딩
- View에 선언된
data
를 가지고,tag
의 속성을 동적으로 조작할 수 있다.
⚠️html tag
에서 제공되는 모든 속성에 대해서 v-bind를 이용해 연결 가능하다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<template>
<div :class="{ textClass: true }">class binding</div>
<div :id="{ textId: true }">id binding</div>
<div :style="textStyle">style binding</div>
</template>
<script>
export default {
data() {
return {
textClass: "primary",
textId: '{ color: "red"}',
textStyle: "dynamic"
};
}
};
</script>
<style scoped>
.primary {
color: coral;
}
.dynamic {
color: purple;
}
</style>
- Mustache tag
- 데이터 바인딩 {{ }}
Vue Application Instance
안에 선언된 값들은 콧수염괄호를 통해 표시될 수 있다.
Vue CLI(Command Line Interface)
- 🍍 npm
- 자바스크립트 라이브러리를 로컬에 설치하기 위한 도구
1
2
3
4
5
6
npm install -g @vue/cli
vue create project_name > Default([Vue 3] babel, eslint)
cd project_name
npm run serve
- 📕 Vue CLI는 내부적으로 웹팩(Web Pack)을 기반으로 하고 있다
- 웹팩이란 Frontend Framework에서 가장 많이 사용되는 ‘모듈 번들러’다.
모듈 번들러란 웹 애플리케이션을 구성하는 모든 자원을 각각의 모듈로 보고, 이를 조합해서 병합된 하나의 결과물을 만드는 도구를 말한다.즉, 모듈 번들링이란 여러 자원들을 하나의 파일로 병합 및 압축해주는 동작을 말한다.
🍍 모듈이란 특정 기능을 갖는 작은 코드 덩어리를 말한다.🎯 웹팩을 쓰는 목적
- 모든 자원을 각각의 모듈로 보기 때문에 모듈 단위로 파일을 관리할 수 있다. 즉, 파일(모듈) 단위로 자바스크립트 변수를 관리하여 변수 중복선언이나, 의도치않은 값 할당을 예방할 수 있다.
- 웹 리소스(HTML, JavaScript, Css, 이미지 etc)를 하나로 묶고, 압축 및 변환하여 최적화된 형태로 만들어 주는 역할을 한다.
- 웹사이트의 로딩 속도를 높이기 위해, 브라우저에서 서버로 요청하는 파일 수를 줄이는게 중요한데, 파일을 병합하고 압축하는 작업을 수행하여 파일 수를 줄일 수 있다.
⚠️ Vue 프로젝트에 설정되어 있는 웹팩 옵션들을 vue.config.js에서 수정할 수 있다.
- 📕 Vue 프로젝트를 생성하게 되면 package.json파일이 생성된다.
🧆 package.json
파일에는 생성한 프로젝트의 메타정보와 프로젝트가 의존하고 있는 모듈들에 대한 정보가 json 형태로 작성되어 있다.
- custom scripts 명령어
- dependencies / devdependencies
- eslintConfig 자바스크립트 문법 검사 도구
- browserslist 브라우저 호환성
- 📘 node_modules
- package.json에 있는 모듈과 그 모듈들이 의존하고 있는 모든 모듈을 포함하고 있다.
npm으로 새로운 모듈을 설치하게 되면 자동으로 package.json과 node_modules에 추가된다.
⚠️ npm install 명령어로 node_modules를 언제든지 생성할 수 있다.
- 📘 package-lock.json
- package.json 파일이 생성되는 시점의 node_modules에 대한 정보를 가지고 있다.
❓ 왜 있는 걸까
package.json 파일의 의존성 선언에는 version range(특정 버전이 아닌 버전의 범위)가 사용된다.
이 말은, 개발 환경에 따라 설치된 모듈의 버전이 다를 수 있다는 것을 의미하는데,
package-lock.json 파일이 해당 프로젝트에 설치되어야하는 의존성의 정확한 버전을 관리해준다. (프로젝트가 동일한 의존성을 가질 수 있도록 해준다.)
⚠️ npm을 사용해서 package.json 혹은 node_modulles를 수정하면 package-lock.json도 자동으로 업데이트된다.
📕 애플리케이션의 진입점은 📂public > index.html 파일이다.
index.html
1
2
3
<div id="app">
<!-- 여기에 Vue CLI로 빌드된 결과물(bundle)이 채워진다. -->
</div>
- 즉, id가 app인 태그 하위에 Vue Application Instance를 만들고 붙여야 하는데 이는
📂src > main.js
파일에 작성한다.
🐝 main.js
1
2
3
4
import { createApp } from "vue"; // package.json안의 dependencies에 vue가 있기 때문에 import 할 수 있다.
import App from "./App.vue"; // .vue를 싱글 파일 컴포넌트라 한다.
createApp(App).mount("#app");
싱글파일 컴포넌트(.vue)
화면 특정 영역에 대한 HTML, CSS, JavaScript를 하나의 파일로 관리한다.
🦇 App.vue
1
2
3
4
5
6
7
8
9
10
11
<template>
<!-- Vue 컴포넌트의 표현단, Vue 템플릿 문법 -->
</template>
<script>
// Vue 컴포넌트 데이터
</script>
<style>
/* 뷰 템플릿 스타일링 */
</style>