props를 이용해서 상위컴포넌트에서 하위컴포넌트에 데이터를 전달하고, event를 통해 하위컴포넌트에서 상위컴포넌트로 전달하는 것은
React와 동일하다.
Vue에서는 props를 어떻게 전달하는지 알아보자
<body>
<template id="listTemplate">
<li>{{message}}</li>
</template>
<script>
Vue.component("list-component", {
template: "#listTemplate",
props: ["message","count"],
});
</script>
<div id="app">
<ul>
<list-component message="Hello"></list-component>
<list-component message="씬짜오"></list-component>
<list-component message="니하오마"></list-component>
<list-component count="21"></list-component>
</ul>
</div>
</body>
<script>
Vue.config.devtool = true;
const vm = new Vue({
el: "#app",
});
</script>
props속성에 배열을 이용해 props명을 전달한다.
주의할 점이 있다면 컴포넌트 작성시 속성명을 부여할 때 카멜케이스를 사용했다면 태그에서 속성명을 사용할 땐 케밥케이스를 사용해야 한다는 것이다.
myProps라는 이름으로 전달을 했을 때, my-props로 사용한다.
React에서 HTML5의 dataset을 사용할 때 data-my-props는 dataset.myProps로 사용했던 것과 같다.
HTML이 대소문자 구분을 안하기 때문이다.
속성명을 배열 형태로 간단하게 전달할 수도 있지만, 엄격한 유효성 검증이 필요하다면 객체형태로 사용할 수 있다.
<body>
<template id="listTemplate">
<li>{{message}}</li>
</template>
<script>
Vue.component("list-component", {
template: "#listTemplate",
props: {
message: { type:String, default:"안녕하세요"},
count: { type:Number, required: true },
});
</script>
<div id="app">
<ul>
<list-component message="Hello"></list-component>
<list-component message="씬짜오"></list-component>
<list-component message="니하오마"></list-component>
</ul>
</div>
</body>
<script>
Vue.config.devtool = true;
const vm = new Vue({
el: "#app",
});
</script>
직관적이기 때문에 쉽게 용도를 알 수 있다. 기본값과 필수값을 설정하고있다.
Vue개발자도구를 열어보면
list-components 컴포넌트에서는 {{}}
를 이용해서 표현하고 있어 number로 타입을 정했지만 문자열로 출력된다.
이 문제는 v-bind
디렉티브를 이용하면 해결된다. :count 를 이용해서 속성을 전달해보면 해결된다.
...
<list-component message="신짜오" :count="21" />
data는 함수로 정의해야한다. 객체로 정의하면 재사용시에 동일한 객체를 참조하기 때문에 문제가 발생한다. 함수로 정의해 객체를 리턴하게 만들어야 매번 새로운 객체를 생성하기 때문에 재사용 시마다 각각 상태값을 사용할 수 있다.
props의 default에서도 마찬가지다 배열이나 객체를 전달 할 때 default를 부여하려면 반드시 함수를 이용해야 한다.
props를 전달받고나면 String으로 변경되어있는 문제는 디렉티브를 사용해 String으로 전달(리터럴이 자바스크립트로 인식되지 않아서)되지 않도록하자. 일반적으로 변수에 담아서 디렉티브를 통해 전달하므로 문제가 안된다.
<body>
<!-- 자식 컴포넌트 -->
<template id="childTemplate">
<div>
<button v-on:click="clickEvent" v-bind:data-lang="buttonInfo.value">
{{ buttonInfo.text }}
</button>
</div>
</template>
<script>
Vue.component("child-component", {
template: "#childTemplate",
props: ["buttonInfo"],
methods: {
clickEvent: function (e) {
this.$emit("timeclick", e.target.innerText, e.target.dataset.lang);
},
},
});
</script>
<!-- 부모 컴포넌트 -->
<template id="parent-template">
<div>
<child-component
v-for="s in buttons"
v-bind:button-info="s"
@timeclick="timeclickEvent"
>
</child-component>
<hr />
<div>{{ msg }}</div>
</div>
</template>
<script>
Vue.component("parent-component", {
template: "#parent-template",
props: ["buttons"],
data: function () {
return { msg: "" };
},
methods: {
timeclickEvent: function (k, v) {
this.msg = k + ", " + v;
},
},
});
</script>
<div id="app">
<parent-component :buttons="buttons"></parent-component>
</div>
<script>
const rootVue = new Vue({
el: "#app",
data: {
buttons: [
{ text: "Hello", value: "영어" },
{ text: "안녕", value: "한국어" },
{ text: "씬짜오", value: "베트남어" },
{ text: "니하오", value: "중국어" },
],
},
});
</script>
</body>
React와는 다르게 props를 전달할 때 명시적으로 이벤트임을 알려줘야 하는 것을 주의하자.