컴포넌트 생성
– 컴포넌트 생성방법 알기
– 부모가 자식 컴포넌트를 가지는 방법 알기
|
|
root 컴포넌트에 있는 부분을 voter 라는 새로운 컴포넌트를 만들고 이동한다.
컴포넌트의 구성요소는 뷰를 담당하는 template와 모델 영역인 data + methods로 구성된다.
그리고 root 컴포넌트에서 이 voter 컴포넌트를 <voter></voter>로 가지게 된다.
이와같이 컴포넌트는 트리형태를 가지게 된다.
실행을 해보면 두가지의 에러가 생기게 된다.
vue.js:597 [Vue warn]: The “data” option should be a function that returns a per-instance value in component definitions.
vue.js:597 [Vue warn]: Error compiling template:
<h2>{{name}}: {{ result }}</h2>
<button @click=”agree”>Agree</button>
<button @click=”disagree”>DisAgree</button>
– Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead.
data는 funcion이여야 한다는것이고 template는 하나의 root element를 가져야 한다는것이다.
1 2 3 4 5 6 7 8 9 10 11 12 |
template: `<div> <h2>{{name}}: {{ result }}</h2> <button @click="agree">Agree</button> <button @click="disagree">DisAgree</button> </div>`, data: function() { return { name: 'hong kil dong', result: null } }, |
부모 자식간의 기본적인 통신 방법
실제 개발을 하다보면 모든 데이터는 root 혹은 부모가 데이터를 갖고 있는게 로직처리를 하는게 더 쉬워진다.
예) 틱택톡 게임
9칸으로 구성된 틱택토 게임은 한칸을 자식 컴포넌트로 구성하고 자식 컴포넌트가 가질수 잇는 속성은 O, X 두가지라고 했을때
자식 컴포넌트로 부터 9개의 인스턴스를 구성하고 클릭시 이벤트를 발생하여 O, X를 가지게 한다고 가정해보자.
실제로 게임 로직은 O 혹은 X로 구성된 부분이 가로, 세로, 대각선을 만들었는지를 체크해야만 한다. 그런데 이 값을 자식 컴포넌트가 갖고 있으므로 이 값이 바뀔때마다 부모 컴포넌트에게 알려줘야 한다.
이렇게 할 바에야 차라리 이 값을 처음부터 부모가 갖고 있다가 자식한테 알려주는 방법이 더 효율적이다.
부모가 자식에게 모델 데이터 값을 보내 주는 방법은 v-bind:자식변수=”부모변수” 이다.
자식이 이 변수를 받는 방법은 props로 받게 된다.
위에 name과 result 모델을 이렇게 정의해보자.
먼저 부모 컴포넌트에게 name과 result 데이터값을 정의한다.
1 2 3 4 5 6 7 8 9 10 |
var app = new Vue({ el: '#app', data: { name: 'hong kil dong', result: null }, methods: { } }); |
그리고 자식 컴포넌트에서는 이 값을 물려받도록 한다.
|
|
그리고 agree, disagree 버튼을 눌러보자.
잘 동작하는것처럼 보이지만 콘솔창을 보면 다음과 같은 에러가 보인다.
vue.js:597 [Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop’s value. Prop being mutated: “result”
found in
—> <Voter>
<Root>
props 데이터를 직접 변경하는것을 피하라. 왜냐하면 부모 컴포넌트가 다시 렌더링 될때마다 오버라이트 될것이다.
부모가 result 값을 변경하면 그 값이 부모도 바뀌고 자식도 바뀌지만 자식이 이 값을 바꾸면 바뀐 값이 부모에게는 전달이 안된다는 의미이다.
즉, 단방향 데이터 흐름이다.
부모컴포넌트에 result를 바인딩해서 테스트해보거나 크롬 devtools를 통해서 확인해보자.
크롬 devtools 는 확장팩으로 추가해서 사용할 수 있다.
그래서, result 값을 변경하고 싶으면 자식이 부모에게 바꿔달라고 요청을 해야 한다.
모든 Vue 인스턴스는 다음과 같은 이벤트 인터페이스를 구현한다.
$on(eventName)을 사용하여 이벤트를 감지
$emit(eventName)을 사용하여 이벤트를 트리거(발생)
하지만, 하나의 예외가 있는데 $on 일 경우에는 자식 컴포넌트의 이벤트를 감지 하지 못한다. 그래서 v-on으로 바인딩해야 한다.
먼저 부모 컴포넌트에 두개의 이벤트를 추가한다.
v-on으로 on-agree, on-disagree 이벤트를 감시하고 있다가 해당 이벤트가 발생하면 handleAgree, handleDisagree 메서드를 호출하라는 의미이다.
|
|
자식 컴포넌트에서는 클릭이벤트가 발생했을때 on-agree, on-disagree 이벤트를 emit 한다.
devtools에서 제대로 이벤트가 발생하는지 확인하자.
1 2 3 4 5 6 7 8 |
methods: { agree: function(){ this.$emit('on-agree'); }, disagree: function () { this.$emit('on-disagree'); } } |
전체 소스는 다음과 같다.
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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
<!DOCTYPE html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>JS Bin</title> </head> <body> <div id="app"> <h1>투표자</h1> <span>result: {{result}}</span> <voter v-bind:name="name" :result="result" v-on:on-agree="handleAgree" v-on:on-disagree="handleDisagree"></voter> </div> <script src="https://unpkg.com/vue/dist/vue.js"></script> </body> </html> <script> Vue.component('voter', { template: `<div> <h2>{{name}}: {{ result }}</h2> <button @click="agree">Agree</button> <button @click="disagree">DisAgree</button> </div>`, props: ['name', 'result'], data: function() { return { } }, methods: { agree: function(){ this.$emit('on-agree'); }, disagree: function () { this.$emit('on-disagree'); } } }); var app = new Vue({ el: '#app', data: { name: 'hong kil dong', result: null }, methods: { handleAgree: function(){ this.result = 'agree'; }, handleDisagree: function () { this.result = 'disagree'; } } }); </script> |