초창기 자바스크립트 프레임워크에선 하나의 화면 = 하나의 view로 간주
Vue.js의 경우 하나의 화면 = 하나 혹은 다수의 컴포넌트
vue.js의 중요한 특징은 컴포넌트마다 고유한 스코프(유효 범위)가 존재. 즉 컴포넌트끼리 직접 참조가 불가능하다.
따라서 vue에서 자체적으로 정의한 컴포넌트 데이터 전달 방법을 이용해 통신해야 한다.
Vue는 컴포넌트 단위로 화면이 구성되고 하나의 컴포넌트는 자식 컴포넌트를 갖게 될 수 있다. 이러한 경우를 부모-자식 컴포넌트 관계 or 상-하위 컴포넌트 관계라고 한다.
화면을 구성하다보면 이렇게 구성할 경우가 많은데 그 과정에서 서로 데이터가 공유될 때가 많다.
Vue.js에서 부모-자식 컴포넌트 관계는 props는 아래로, events 위로 라고 요약 할 수 있다. 부모는 props를 통해 자식에게 데이터를 전달하고 자식은 events를 통해 부모에게 메시지(이벤트)를 보낸다.
기본적으로 Vue는 단방향 데이터 흐름(One-way Data Flow)의 특징을 갖는다. 이는 컴포넌트의 단방향 통신을 의미하는데 컴포넌트 간 데이터 전달 시 항상 상위 컴포넌트에서 하위 컴포넌트로 데이터가 전달되도록 구조화되어 있다는 것을 말한다. 따라서 상-하위 컴포넌트 구조에선 하위 컴포넌트에서 상위 컴포넌트로 데이터 전달은 기본적으로 제한되어 있다.
먼저 props를 이용해 상위컴포넌트에서 하위컴포넌트로 데이터를 전달하는 코드를 작성해 보겠다.
[Props : 상위 -> 하위컴포넌트]
다음과 같이 컴포넌트 관계 및 요구사항을 정의했다.
코드 구현 과정은 다음과 같다.
<하위컴포넌트 v-bind:[하위컴포넌트에서 정의한 props 속성이름]="상위컴포넌트에서 전달할 data 속성key값"></하위컴포넌트>
[Home.vue]
<template>
<v-btn :href="path">네이버연결</v-btn> <!-- v-bind를 통해 href 속성 조작(path) -->
</template>
<script>
export default {
props: ['linkInfo'], // 하위컴포넌트에서 linkInfo라는 이름으로 데이터를 받겠다라고 정의
data() {
return {
path: this.linkInfo //상위컴포넌트에서 linkInfo라는 이름으로 넘어온 props value를 path에 대입
}
}
}
</script>
[App.vue]
<template>
...코드 생략
<v-app>
<v-main>
<!-- 하위컴포넌트에서 정의한 props 이름인 linkInfo에 전달할 data 속성 value 설정-->
<Home v-bind:linkInfo="path"></Home>
</v-main>
</v-app>
</template>
<script>
import Home from "@/components/preset/Home";
export default {
name: 'App',
components: {
Home
},
data: () => ({
path: 'https://naver.com' // props를 통해 하위컴포넌트에 전달할 데이터
}),
};
</script>
<style scoped>
</style>
[결과]
사진에서 처럼 네이버연결 버튼에 props를 통한 href 속성이 변경되어 링크연결이 잘되어 있다.
vue-devtools를 통해서도 확인해보면 아래와 같이 props가 잘 전달되는 것을 알 수 있다.
[APP - 상위 컴포넌트]
[Home - 하위 컴포넌트]
다음으로 event를 이용해 하위컴포넌트에서 상위컴포넌트로 통신 방법에 대해 살펴보도록 하자. 서두에 설명했던 것처럼 Vue의 단방향 데이터 흐름 특성으로 인해 하위 -> 상위 컴포넌트로의 데이터 전달은 제한되어있다. 하지만 이벤트를 통해 상위 컴포넌트의 method를 수행할 수 있다.
[event : 하위 -> 상위컴포넌트]
다음과 같이 컴포넌트 관계 및 요구사항을 정의했다.
[하위 컴포넌트 : InputArea.vue]
<template>
<v-container fluid>
<v-text-field label="검색바" v-model="inputText"></v-text-field>
<!-- 정의된 이벤트를 호출할 버튼 생성 -->
<v-btn class="ml-2" v-on:click="transferEvent">이벤트호출</v-btn>
</v-container>
</template>
<script>
import EventBus from "@/eventBus";
export default {
data () {
return {
inputText: ''
}
},
name: "InputArea",
methods: {
transferEvent: function () { // 버튼 클릭시 'show-log'라는 이벤트 발생
this.$emit('show-log');
}
}
}
</script>
<style scoped>
</style>
[상위 컴포넌트 : App.vue]
<template>
<v-app id="inspire">
...코드 생략
<v-main>
<!-- v-on을 통해 하위컴포넌트 이벤트 지정 및 발생 시 호출될 상위 컴포넌트 method(AlertMsg) 지정 -->
<InputArea v-on:show-log="AlertMsg"></InputArea>
</v-main>
</v-app>
</template>
<script>
import InputArea from "@/components/preset/InputArea";
export default {
name: 'App',
components: {
... 코드생략
InputArea
},
data: () => ({
drawer: null,
path: 'https://naver.com'
}),
methods : {
AlertMsg : function () { // 하위컴포넌트에서 발생한 이벤트 수신 시 호출할 method
alert("Alert 이벤트 발생");
}
}
};
</script>
<style scoped>
</style>
[결과]
VueDevtools에서도 이벤트가 발생한 것을 알 수 있다.
지금까지 상-하위 컴포넌트 통신 방법을 살펴보았다.
Vue.js 공식 문서에도 props 사용방법, event 관련 예제가 나와있지만 단순한 테스트 코드가 아니라 실제 사용할 법한 화면 기능에 구현해보면서 좀 더 이해가 잘 된 것 같다. 이론적인 부분은 vue.js 공식 문서를 참고하면 좋을 것 같다.
[참고]
[Vue.js] 4. Event Bus를 통한 컴포넌트 통신 (0) | 2020.08.13 |
---|---|
[Vue.js] 2. Vue 프로젝트 디렉토리 구조 (0) | 2020.08.12 |
[Vue.js] 1. Vue.js 개발 환경 설정(with IntelliJ) (0) | 2020.08.12 |