6 컴포넌트 통신 방법 - 응용
source: categories/study/vue-beginner-lv1/vue-beginner6.md
6.1 같은 컴포넌트 레벨 간의 통신 방법
이번 시간엔 앞에서 배웠던 상위 컴포넌트, 하위 컴포넌트의 통신 방법에 이어서 같은 레벨의 컴포넌트일 경우엔 통신을 어떻게하는지 알아보도록 하겠습니다.
Root
라고 하는 것은 new Vue();
로 생성한 인스턴스입니다.
Root
라는 인스턴스에서 하위 컴포넌트로 AppHeader
, AppContent
를 등록했을 때, AppContent
에서 AppHeader
로 어떻게 data
를 전달할 수 있는지
위와 같이 AppContent
컴포넌트에서 AppHeader
로 10이라는 data
를 전달해보도록 하겠습니다.
- 상위에서 하위 컴포넌트로는
props
- 하위에서 상위 컴포넌트로는
event
같은 레벨에서의 컴포넌트 통신은 과연 어떻게이루어질지 한번 고민해보시면 좋을거 같습니다.
6.2 같은 컴포넌트 레벨 간의 통신방법 구현 1
위와 같이 예제 파일을 만들고 같은 레벨에서의 컴포넌트 간의 통신 방법에 대해 살펴보겠습니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5, user-scalable=no">
<title>Document</title>
</head>
<body>
<div id="app">
{{str}}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
str: 'hi'
}
})
</script>
</body>
</html>
위와 같이 작성하면 화면에 출력이 가능하다는 걸 볼 수 있었죠? (reactivity)
다시 아래와 같이 코드를 작성해줍니다.
이 상황에서 아까 말씀드린 것처럼 AppContent
에서 AppHeader
로 10
을 넘길 겁니다.
위 appContent
에서 특정 버튼을 눌렀을 때,
일단 위와 같이 appContent
에 button
을 만들어줍니다.
위와 같이 pass
라고 하는 버튼이 생겼습니다.
app-content
라고 하는 컴포넌트 안에 생긴 버튼입니다.
이 pass
라는 버튼을 눌렀을 때 신호를 발생시킬 겁니다.
위와 같이 v-on:click="passNum"
코드를 통해 해당 button
을 클릭했을 때 passNum
함수를 실행시킵니다.
그리고 위와 같이 this.$emit('pass', 10);
이라고 작성하고 개발자 도구를 통해 실제로 어떻게 동작하는지 확인해봅시다.
위와 같이 pass button을 클릭하면 pass라는 이벤트가 발생하고, payload안에 10이라는 값이 들어옵니다.
이렇게 하는 이유는
이렇게 AppContent에서 AppHeader로 바로 10이란 값을 쏘아주면 좋을텐데, 지금 이 길이 막혀있잖아요? 흐름 추적이 어렵기 때문에 컴포넌트 통신을 제한했다고 말씀드렸었죠?
그래서 위와 같이 AppContent에서 일단 Root로 10을 올려보내야됩니다.
그리고나서 Root에서 AppHeader로 내려주시면됩니다.
이때 AppContent에서 Root로 10을 올릴때는 event를 통해서 올리고,
Root에서 AppHeader로 10을 내릴 때는 props를 통해서 내린다.
즉, 처음에 말씀드린 것처럼 하위 컴포넌트에서 상위 컴포넌트로 통신할 땐 event, 상위 컴포넌트에서 하위 컴포넌트로 통신할 땐 props가 되는 것입니다.
Root에서 AppHeader로 props를 내리시려면 data를 선언하셔야됩니다. 그 관점에서 이어서 보도록 하겠습니다.
위 new Vue()
라고 하는 것이 Root
컴포넌트입니다.
AppContent의 상위 컴포넌트인 Root에 data를 선언하셔야됩니다.
위와 같이 Root
에 data
, num
을 넣어줍니다.
지금 상황 - app-content
컴포넌트에서 발생하는 event
가 Root
로 올라오는 상황.
이 다음 시간에 data
를 props
로 내리는 것까지 해보겠습니다.
6.3 같은 컴포넌트 레벨 간의 통신 방법 구현 2
앞시간에 data의 num 값, 그리고 pass 이벤트 발생까지 확인했습니다.
위와 같이 app-content 컴포넌트에 v-on:pass=""
를 통해서 pass 이벤트를 받고 상위 컴포넌트의 methods를 실행시킬 수 있다고 했습니다.
여기서 app-content 컴포넌트의 상위 컴포넌트라함은 Root 컴포넌트가 될 것입니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5, user-scalable=no">
<title>Document</title>
</head>
<body>
<div id="app">
<app-header></app-header>
<app-content v-on:pass="deliverNum"></app-content>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var appHeader = {
template: '<div>header</div>',
}
var appContent = {
template: '<div>content <button v-on:click="passNum">pass</button></div>',
methods: {
passNum: function () {
// 아래와 같이 작성했을 때 button을 클릭하면 pass라는 이벤트가 발생하고 payload 안에 10이라는 값이 들어옵니다.
// 이렇게 하는 이유는 appContent 컴포넌트에서 appHeader 컴포넌트로 바로 10이라는 값을 쏘아주면 좋을텐데, 지금 이 길이 막혀있잖아요?
// 흐름 추적이 어렵기 때문에 컴포넌트 통신을 제한한다고 말씀드렸었죠?
// 그래서 일단 아래와 같이 event를 통해 appContent 컴포넌트에서 Root 컴포넌트로 10이란 값을 올려보내는겁니다.
// -- 그리고나서 Root 컴포넌트에서 appHeader 컴포넌트로 내려주시면됩니다. --
// 이때 appContent 컴포넌트에서 Root 컴포넌트로 10을 올릴 때는 event를 통해서 올리고,
// Root 컴포넌트에서 appHeader로 10을 내릴 때는 props를 통해 내립니다.
// 즉, 처음에 말씀드린 것처럼 하위 컴포넌트에서 상위 컴포넌트로 통신할 땐, event, 상위 컴포넌트에서 하위 컴포넌트로 통신할 땐 props가 되는겁니다.
// -- Root에서 appHeader로 props를 내리시려면 data를 선언하셔야됩니다. --
this.$emit('pass', 10);
}
}
}
new Vue({
el: '#app',
components: {
'app-header': appHeader,
'app-content': appContent,
},
data: {
num: 0,
},
methods: {
deliverNum: function (value) {
this.num = value;
}
}
})
</script>
</body>
</html>
위와 같이 정의하면 app-content 컴포넌트를 클릭했을 때, Root 컴포넌트의 num이 10으로 바뀌게됩니다.
그리고 event 로그에는 pass라는 이벤트가 올라온 것을 볼 수 있다. 10이라는 값과 함께.
이제 num이라는 data를 app-header에 전달해주기만하면 된다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5, user-scalable=no">
<title>Document</title>
</head>
<body>
<div id="app">
<app-header v-bind:propsdata="num"></app-header>
<app-content v-on:pass="deliverNum"></app-content>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var appHeader = {
template: '<div>header</div>',
props: ['propsdata']
}
var appContent = {
template: '<div>content <button v-on:click="passNum">pass</button></div>',
methods: {
passNum: function () {
// 아래와 같이 작성했을 때 button을 클릭하면 pass라는 이벤트가 발생하고 payload 안에 10이라는 값이 들어옵니다.
// 이렇게 하는 이유는 appContent 컴포넌트에서 appHeader 컴포넌트로 바로 10이라는 값을 쏘아주면 좋을텐데, 지금 이 길이 막혀있잖아요?
// 흐름 추적이 어렵기 때문에 컴포넌트 통신을 제한한다고 말씀드렸었죠?
// 그래서 일단 아래와 같이 event를 통해 appContent 컴포넌트에서 Root 컴포넌트로 10이란 값을 올려보내는겁니다.
// -- 그리고나서 Root 컴포넌트에서 appHeader 컴포넌트로 내려주시면됩니다. --
// 이때 appContent 컴포넌트에서 Root 컴포넌트로 10을 올릴 때는 event를 통해서 올리고,
// Root 컴포넌트에서 appHeader로 10을 내릴 때는 props를 통해 내립니다.
// 즉, 처음에 말씀드린 것처럼 하위 컴포넌트에서 상위 컴포넌트로 통신할 땐, event, 상위 컴포넌트에서 하위 컴포넌트로 통신할 땐 props가 되는겁니다.
// -- Root에서 appHeader로 props를 내리시려면 data를 선언하셔야됩니다. --
this.$emit('pass', 10);
}
}
}
new Vue({
el: '#app',
components: {
'app-header': appHeader,
'app-content': appContent,
},
data: {
num: 0,
},
methods: {
deliverNum: function (value) {
this.num = value;
}
}
})
</script>
</body>
</html>
pass 버튼을 클릭하면 event 로그에서 pass 이벤트가 잘 발생한 것을 볼 수 있다.
Root라는 컴포넌트에 num이라고하는 data 속성이 잘 바뀐 것을 볼 수 있다.
마지막으로 app-header의 propsdata 값에 10이 제대로 넘어온 것을 확인할 수 있다.