안녕하세요! 저번 포스팅으로 Vue.js가 무엇이고 왜 사용하는지 더 나아가 Vue Instance에 대해서 알아보았습니다.
오늘은 Vue 컴포넌트와 컴포넌트간의 통신방법에 대해 알아보겠습니다.
이전 포스팅 👀
💬
프론트앤드 개발자가 되기위해 vue에 처음 입문하게된 초보 개발자입니다. 많은 강의들을 찾아봤지만 Vue.js는 입문자들이 배우기엔 정보가 부족한 것 같아 인프런 '캡틴판교 (장기효)'님의 Vue.js 시작하기를 보며 공부하고 있습니다. 따라서 포스팅 내용이 '캡틴판교 (장기효)'님 강의를 참고하여 작성되어집니다!
1. Vue Component 란?
화면의 영역을 구분하여 개발할 수 있는 뷰의 기능 → 컴포넌트 간 관계발생
컴포넌트 기반으로 화면을 개발하여 코드의 재사용성을 높이고 빠르게 화면 제작이 가능 (최근 대부분 모던 프레임워크 = 컴포넌트 기반)
**재사용성의 좋은 점 : 코드의 반복이 줄어 가독성이 좋고 최대한 많은 화면을 뽑아냄
컴포넌트 등록 방법 : 전역 / 지역
▶ 전역 컴포넌트 : 인스턴스를 생성할 때마다 따로 등록할 필요 X
→ 전역으로 필요한 플러그인이나 라이브러리화를 시켜야하는 경우 사용
Vue.Component: ( '컴포넌트 이름' : '컴포넌트 내용' )
▶ 지역 컴포넌트 : 여러 개의 속성이 들어가 서비스를 구현하는 로직이 하나가 아닌 여러개이므로 components!!
new Vue({ ... , components : '컴포넌트 이름' : '컴포넌트 내용' , ... })
<body>
<div id="app">
<!--app Header component 태그!! 컴포넌트의 내용이 반영되어 나타남-->
<app-header></app-header>
<!-- <div> Content </div> -->
<app-content></app-content>
<app-footer></app-footer>
</div>
<div id="app2">
<app-header></app-header>
<app-footer></app-footer>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
// 전역 component 등록방법 (많이 쓰이지 않음)
// Instance 를 생성할 때마다 따로 등록 X 기본적으로 모든 Instance에 등록되어있음.
// Vue.component('컴포넌트 이름', 컴포넌트 내용);
Vue.component('app-header',{
// tamplate : 화면에 들어가는 html 태그
template: '<h1>Header</h1>'
});
Vue.component('app-header', {
// tamplate : 화면에 들어가는 html 태그
template: '<div>Content</div>'
});
new Vue({
el: '#app',
// {} 객체 기호
// 지역 component 등록방법
// component's'!!!!! s주의 !!!!
components: {
//정의형태 : 'key' : 'value'
// '컴포넌트 이름' : '컴포넌트 내용'
'app-footer': {
template: '<footer>Footer</footer>'
}
},
});
new Vue({
el: '#app2',
components: {
// 지역 component는 Instance마다 새로 생성!!!
'app-footer': {
template: '<footer>Footer</footer>'
}
},
});
</script>
</body>
2. Component 통신방법
뷰 컴포넌트는 각각 고유한 데이터의 유효범위를 갖기에 컴포넌트 간 데이터를 주고 받기위해 규칙을 따라야합니다.
props 속성 : 상위에서 하위로 데이터를 내려줌
event 발생 : 하위에서 상위로 이벤트를 올려줌
💡 규칙은 컴포넌트 관계의 중요한 부분입니다.
예를들어, 아래의 사진과 같은 컴포넌트 구조가 있다면,
🟦
파랑화살표와 같이 N방향으로 통신했을 경우
특정 컴포넌트의 변화에 따라 나머지 컴포넌트가 유기적으로 데이터를 계속 주고 받는다면 데이터의 방향을 예측하기 힘듦.
특정 상태 데이터가 바뀌었을 때 그로 인한 버그 추적이 어렵다는 단점이 있습니다.
🟩
하지만 초록색 화살표처럼 컴포넌트 규칙이 생겨 통신한다면? 데이터의 흐름을 추적할 수 있습니다.
(아래에서 위로 이벤트 발생, 위에서 아래로 프롭스 속성에 데이터를 넣어 전달)
3. Props
Props 속성의 특징은 상위 컴포넌트의 data인 message를 props로 전달받았을 때,
상위 data message가 변경되면 하위에 전달된 props도 바뀌게 되는 Vue의 Reactivity가 반영되어 있습니다.
props 문법
<app-header v-bind : 프롭스 속성 이름 = "상위 컴포넌트의 데이터 이름"></app-header>
<body>
<div id="app">
<!--프롭스(props) 문법
<app-header v-bind:프롭스 속성 이름="상위 컴포넌트의 데이터 이름"></app-header>
app-header기준 상위 컴포넌트 : Root -> 데이터 이름 : message
props 속성이름은 변수에 만들어줌-->
<app-header v-bind:propsdata="message"></app-header>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
// 변수이름은 카메인케이스 : 두번째단어는 대문자로 표시 (네이밍기법)
// 컴포넌트 통신을 이용하면 코딩이 길어지므로
// 가독성을 위해 변수에 담아 활용
var appHeader = {
// {{}} 데이터바인딩
template: '<h1>{{ propsdata }}</h1>',
props: ['propsdata']
}
new Vue({
el: '#app',
// components: {
// 'app-header' : {
// template: '<h1>Header</h1>'
// }
// }
components: {
'app-header': appHeader
},
data: {
message: 'hi'
}
});
</script>
</body>
그럼 더 나아가 상위 컴포넌트인 Root의 message 데이터를 <app-header>에 num의 값은 <app-content>에 각각 전달을 해본다면?
<body>
<div id="app">
<app-header v-bind:propsdata="message"></app-header>
<app-Content v-bind:propsdata="num"></app-Content>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var appHeader = {
template: '<h1>{{ propsdata }}</h1>',
props: ['propsdata']
}
var appContent = {
template: '<div>{{ propsdata }}</div>',
//같은 이름을 사용해도 구분이 가능.
props: ['propsdata']
}
new Vue({
el: '#app',
components: {
'app-header': appHeader,
'app-content' : appContent
},
data: {
message: 'hi',
num : 10
}
});
</script>
</body>
4. event emit
아래에서 위로 컴포넌트 간의 통신(신호)이 발생한다면 event를 발생시키는데 이것을 event emit이라고 합니다.
event emit 문법
<app-header v-on:하위 컴포넌트에서 발생한 이벤트 이름 = "상위 컴포넌트의 메서드 이름"></app-header>
v-on 은 Vue에서 제공하는 속성으로 v-on:click은 "click했을 때"
**이벤트 : 마우스와 키보드의 조작 또는 동작에 의해 일어나는 변화, 현상
<body>
<div id="app">
<!-- 하위에서 상위로 이벤트 발생 : event emit
<app-header v-on:하위 컴포넌트에서 발생한 이벤트이름="상위 컴포넌트의 메서드 이름"></app-header> -->
<app-header v-on:pass="logText"></app-header>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var appHeader = {
// template: '<button>Click Me</button>'
// v-on : vue에서 제공하는 속성
template: '<button v-on:click="passEvent">Click Me</button>',
// 버튼을 클릭했을 때 기본적으로 실행되는 함수
methods: {
passEvent: function(){
this.$emit('pass');
}
}
}
var vm = new Vue ({
el: '#app',
components: {
'app-header': appHeader,
},
methods: {
logText: function() {
console.log('hi');
}
}
});
</script>
</body>
button "click me"를 클릭할 때마다 pass라는 이름의 이벤트가 발생되고 'esc' 버튼을 눌러 콘솔창과 함께 확인한다면 콘솔창에도 클릭 할 때마다 이벤트가 발생하는 것을 확인 할 수 있습니다.
그럼, app-conent의 button을 클릭할 때마다 num=10이 하나씩 증가하는 이벤트를 Root로 전달해 보도록 하겠습니다.
이때 num = 10 인 data 값을 this로 접근하여 구현해줍니다.
<body>
<div id="app">
<p>{{ num }}</p>
<!-- 하위에서 상위로 이벤트 발생 : event emit
<app-header v-on:하위 컴포넌트에서 발생한 이벤트이름="상위 캄포넌트의 메서드 이름"></app-header> -->
<app-header v-on:pass="logText"></app-header>
<app-content v-on:increase="increaseNum"></app-content>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var appHeader = {
// template: '<button>Click Me</button>'
// v-on : vue에서 제공하는 속성
template: '<button v-on:click="passEvent">Click Me</button>',
// 버튼을 클릭했을 때 기본적으로 실행되는 함수
methods: {
passEvent: function(){
this.$emit('pass');
}
}
}
// 버튼을 클릭할 때마다 num 값 증가
// increase : 증가하다
var appContent = {
template: '<button v-on:click="addNumber">ADD</button>',
methods: {
addNumber: function(){
this.$emit('increase');
}
}
}
var vm = new Vue ({
el: '#app',
components: {
'app-header': appHeader,
'app-content': appContent
},
methods: {
logText: function() {
console.log('hi');
},
increaseNum: function () {
// this : 데이터의 num 속성에 접근
this.num = this.num+1;
}
},
data: {
num: 10
}
});
</script>
</body>
.this에 관해 좀 더 알고싶거나 이해가 필요하신 분은 아래의 링크를 참고해주세요.
5. 같은 레벨의 컴포넌트 간의 통신방법은?
우선 같은 레벨상에 위치한 컴포넌트는 바로 전달할 수 없습니다.
상위 컴포넌트에게 event를 발생시키고 상위 컴포넌트의 data를 전달받아야 합니다.
사진에서 처럼 appContent의 데이터값을 event emit문법인 v-on을 이용하여 상위 컴포넌트에 이벤트를 발생(올려주고) 시키고,
appHeader은 props 문법인 v-bind를 이용하여 상위 컴포넌트의 데이터를 전달(내려받고)받아 보겠습니다.
<body>
<div id="app">
<app-header v-bind:propsdata="num"></app-header>
<!--deliverNum(value) 암묵적으로 value을 넘겨줌-->
<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 appConetnt = {
template: '<div>Content<button v-on:click="passNum">pass</button></div>',
methods: {
passNum: function() {
this.$emit('pass', 10);
}
}
}
new Vue({
el: '#app',
components: {
'app-header': appHeader,
'app-content': appConetnt
},
data: {
num: 0
},
methods: {
//pass의 인자값 '10'은 value로 받을 수 있음
deliverNum: function(value) {
this.num = value;
}
}
})
</script>
</body>
부족함이 많은 초보 프론트앤드 개발자에게 좀 더 좋은 방법이나 팁, 조언해주실만한 얘기들이 있다면 거침없이 남겨주세요..
오늘도 조금이라도 성장할 수 있는 초보 개발자였습니다 !
'study > vue.js' 카테고리의 다른 글
[Vue.js] 컴포넌트 : 맨위로 버튼(Scroll Top Button) 만들기 (0) | 2024.01.05 |
---|---|
[Vue.js] 알아보기(4) : Vue 탬플릿문법과 Watch, 최신 Vue CLI (0) | 2020.09.25 |
[Vue.js] 알아보기(3) : Vue Router 와 Axios (0) | 2020.09.07 |
[Vue.js] 알아보기(1) : Vue.js 란 (0) | 2020.09.04 |
[Vue.js] 시작하기 : 기본 개발환경 설정하기 (6) | 2020.09.01 |