- [개발자의품격][부트캠프][1기][21차시] Vue.js #9 | 재사용 컴포넌트2022년 03월 14일 20시 19분 59초에 업로드 된 글입니다.작성자: DandyNow728x90반응형
부모 컴포넌트에서 자식 컴포넌트로 데이터 전달
자식 컴포넌트
부모 컴포넌트로부터 데이터를 받기 위해 <script> 태그 내 export default에 props를 작성한다. props는 부모 컴포넌트에서만 값을 변경할 수 있다.
// src/components/fragments/ChildComponent.vue props: { str: { type: String, default: '' }, num: { type: Number, default: 0 }, isOk: { type: Boolean, default: false }, arr: { type: Array, default: function () { return [] } }, obj: { type: Object, default: function () { return {} } } },
<template> 태그 내에 렌더링 할 <p> 태그 요소를 작성한다.
// src/components/fragments/ChildComponent.vue <div> <p>{{ str }}</p> <p>{{ num }}</p> <p>{{ isOk }}</p> <p>{{ arr }}</p> <p>{{ obj }}</p> </div>
부모 컴포넌트
<script> 태그 내에 자식 컴포넌트(ChildComponent.vue)를 import 하고 components에 키:값으로 'child-component': ChildComponent를 넣는다. data 함수에 키와 값을 작성한다.
// src/views/4_reuse/ParentView.vue <script> import ChildComponent from '@/components/fragments/ChildComponent.vue' export default { components: { 'child-component': ChildComponent }, data() { return { sampleData: 'Hello World', num1: 35, isOk: true, list: [1, 2, 3], person: { name: 'Jeremy' } } } } </script>
<template> 태그 내에 import한 자식 컴포넌트의 키인 <child-component> 태그와 속성을 작성한다. 속성은 data와 바인딩한다.
// src/views/4_reuse/ParentView.vue <template> <div> <!-- 데이터바인딩(:)하지 않으면 문자열로 취급한다. --> <child-component str="Hello" /> <!-- num="3"은 문자열, :num="3"은 정수형이다. --> <child-component :str="sampleData" :num="num1" :isOk="isOk" :arr="list" :obj="person" /> </div> </template>
부모 컴포넌트에서 부모 컴포넌트의 데이터 값 변경
부모 컴포넌트
자식 컴포넌트에서는 props 받는 값을 직접 수정할 수 없다. 부모 컴포넌트에서만 변경할 수 있다.
버튼 "변경"을 추가한다.
// src/views/4_reuse/ParentView.vue <template> <div> <button @click="changeValue">변경</button> ...
변경 버튼을 클릭했을 때 <child-component> 태그의 속성 값 num1을 변경하고자 한다.
// src/views/4_reuse/ParentView.vue <template> <div> ... <child-component :str="sampleData" :num="num1" ...
<script> ... data() { return { ... num1: 35,
methods에 changeValue 함수를 생성하여 데이터 키 num1의 값을 변경하게 한다.
// src/views/4_reuse/ParentView.vue <script> ... methods: { changeValue() { this.num1 = 235 } }
부모 컴포넌트에서 자식 컴포넌트의 데이터 값 변경
자식 컴포넌트
부모 컴포넌트에서는 자식 컴포넌트의 data 값을 직접 변경할 수 있다.
자식 컴포넌트의 data 함수에 str2: 'Jeju' 키와 값을 추가한다. 기본 값은 Jeju이다. 이 값을 부모 컴포넌트에서 'Seoul'로 변경하고자 한다.
// src/components/fragments/ChildComponent.vue <script> ... data() { return { str2: 'Jeju'
str2의 값을 화면에 출력하게 한다.
// src/components/fragments/ChildComponent.vue <template> <div> ... <p>{{ str2 }}</p>
부모 컴포넌트
부모 컴포넌트 <child-component> 태그에 ref="child1"를 추가한다. ref는 마치 자바스크립트의 id와 같은 유일한 값이다(id와는 다르다). child1은 자식 컴포넌트를 가리킨다.
// src/views/4_reuse/ParentView.vue <template> <div> ... <child-component ... ref="child1"
$refs를 통해 child1(자식 컴포넌트)의 데이터 str1에 접근하고 데이터 값을 'Seoul'로 변경한다. 이때 $는 뷰의 글로벌 함수임을 의미한다. 이렇게 부모 ref, $refs를 이용해 부모 컴포넌트에서 자식 컴포넌트의 값에 접근 및 변경할 수 있다. 그렇다면 자식 컴포넌트에서 props를 사용하지 않고 data 함수에 키와 값을 넣어 부모 컴포넌트에서 자식 컴포넌트의 data를 변경하는 방식을 적용하면 되지 않을까? 자식 컴포넌트의 data는 자식 컴포넌트에서 변경이 가능하나 props는 자식 컴포넌트에서 절대 변경할 수 없다. 따라서 부모 컴포넌트에서만 조작이 되어야 하는 data는 props를 통해서만 전달되어야 안전하다.
// src/views/4_reuse/ParentView.vue <script> ... methods: { changeValue() { ... this.$refs.child1.str2 = 'Seoul'
부모 컴포넌트에서 자식 컴포넌트의 함수 접근
부모 컴포넌트에서 자식 컴포넌트의 함수에 접근하는 방법도 $refs를 이용하면 매우 간단하다.
자식 컴포넌트
자식 컴포넌트의 methods에 doPrint() 함수를 선언한다.
// src/components/fragments/ChildComponent.vue <script> ... methods: { doPrint() { console.log('print') } }
부모 컴포넌트
$refs를 이용해 자식 컴포넌트의 doPrint() 함수를 호출한다.
// src/views/4_reuse/ParentView.vue <script> ... methods: { changeValue() { ... this.$refs.child1.doPrint()
자식 컴포넌트에서 부모 컴포넌트로 데이터 전달
부모 컴포넌트
child-component에서는 커스텀 이벤트를 사용할 수 있다. getData() 함수를 실행하는 @change-data 커스텀 이벤트를 지정하였다.
// src/views/4_reuse/ParentView.vue <template> <div> ... <child-component ... @change-data="getData"
부모 컴포넌트의 @change-data 커스텀 이벤트에서 실행할 getData() 함수를 선언한다.
// src/views/4_reuse/ParentView.vue <script> ... methods: { ... getData() { console.log('getData 실행') } }
자식 컴포넌트
클릭 시 자식 컴포넌트의 callParent() 함수를 호출하는 버튼을 생성한다.
// src/components/fragments/ChildComponent.vue <template> <div> ... <button @click="callParent">부모로 데이터 전달</button>
자식 컴포넌트의 "부모로 데이터 전달" 버튼을 클릭했을 때 호출되는 callParent() 함수를 선언한다. 뷰의 글로벌 함수 $emit은 부모 컴포넌트의 <child-component> 내에 선언된 @change-data 커스텀 이벤트를 실행한다.
// src/components/fragments/ChildComponent.vue <script> ... methods: { ... callParent() { this.$emit('change-data') }
$emit은 파라미터로 ('커스텀 이벤트', 데이터)를 받아 부모 컴포넌트로 보낼 수 있다.
// src/components/fragments/ChildComponent.vue <script> ... methods: { ... callParent() { this.$emit('change-data', this.str2) }
부모 컴포넌트
<child-component>에 선언된 @change-data="getData"에 의해 실행되는 getData() 함수의 파라미터로 자식 컴포넌트의 $emit에서 보낸 this.str2를 data로 넣는다.
// src/views/4_reuse/ParentView.vue <script> ... methods: { ... getData(data) { console.log('getData 실행') console.log(data)
※ 부모 컴포넌트 전체 코드
더보기// src/views/4_reuse/ParentView.vue <template> <div> <button @click="changeValue">변경</button> <!-- 데이터바인딩(:)하지 않으면 문자열로 취급한다. --> <child-component str="Hello_1" /> <p>----- 구분선 -----</p> <!-- num="3"은 문자열, :num="3"은 정수형이다. --> <child-component :str="sampleData" :num="num1" :isOk="isOk" :arr="list" :obj="person" ref="child1" @change-data="getData" /> </div> </template> <script> import ChildComponent from '@/components/fragments/ChildComponent.vue' export default { components: { 'child-component': ChildComponent }, data() { return { sampleData: 'Hello_2', num1: 35, isOk: true, list: [1, 2, 3], person: { name: 'Jeremy' } } }, methods: { changeValue() { this.num1 = 235 this.$refs.child1.str2 = 'Seoul' this.$refs.child1.doPrint() }, getData(data) { console.log('getData 실행') console.log(data) } } } </script>
※ 자식 컴포넌트 전체 코드
더보기// src/components/fragments/ChildComponent.vue <template> <div> <p>{{ str }}</p> <p>{{ num }}</p> <p>{{ isOk }}</p> <p>{{ arr }}</p> <p>{{ obj }}</p> <p>{{ str2 }}</p> <button @click="callParent">부모로 데이터 전달</button> </div> </template> <script> export default { components: {}, // props는 부모 컴포넌트에서만 값을 변경할 수 있다. props: { str: { type: String, default: '' }, num: { type: Number, default: 0 }, isOk: { type: Boolean, default: false }, arr: { type: Array, default: function () { return [] } }, obj: { type: Object, default: function () { return {} } } }, data() { return { str2: 'Jeju' } }, setup() {}, created() {}, mounted() {}, unmounted() {}, methods: { doPrint() { console.log('print') }, callParent() { this.$emit('change-data', this.str2) } } } </script>
provide / inject를 이용해 부모 컴포넌트에서 자식 컴포넌트로 데이터 전달
뷰에서 자식 컴포넌트의 depth가 깊어 복잡할 때 props 대신 provide/inject를 이용하면 편리하다. 하지만 inject의 출처를 추적하기가 쉽지 않다. (개인적인 생각으로는 provide() 함수의 키를 작명할 때 컴포넌트 명을 스네이크 표기법으로 넣으면 도움이 될 것 같다.) 보통 2 depth 이상인 경우 사용한다.
부모 컴포넌트
부모 컴포넌트에 자식 컴포넌트 ProvideInject.vue를 import 하고, components에 키:값을 넣는다.
// src/view/5_advanced/ProvideView.vue <script> import ProvideInject from '@/components/fragments/ProvideInject.vue' export default { components: { 'provide-inject': ProvideInject },
<template> 태그 안에 provide-inject 키 태그를 만든다.
// src/view/5_advanced/ProvideView.vue <template> <div> <provide-inject />
provide() 함수를 생성한다. data() 함수는 provide() 함수의 str 키의 data 값을 받기 위해 생성하였다.
// src/view/5_advanced/ProvideView.vue <script> ... data() { return { sampleData: 'AAA' } }, provide() { return { size: 5, str: this.sampleData } },
자식 컴포넌트
자식 컴포넌트의 <script> 태그 안에 inject 키와 배열을 넣는다. 배열 값은 부모 컴포넌트의 provide() 함수에서 보낸 키이다.
// src/components/fragments/ProvideInject.vue <script> ... components: {}, inject: ['size', 'str'],
자식 컴포넌트의 <template> 태그에 <p> 태그로 size, str 값을 렌더링 한다.
// src/components/fragments/ProvideInject.vue <template> <div> <p>{{ size }}</p> <p>{{ str }}</p>
※ 부모 컴포넌트 전체 코드
더보기// src/view/5_advanced/ProvideView.vue <template> <div> <provide-inject /> </div> </template> <script> import ProvideInject from '@/components/fragments/ProvideInject.vue' export default { components: { 'provide-inject': ProvideInject }, data() { return { sampleData: 'AAA' } }, provide() { return { size: 5, str: this.sampleData } } } </script>
※ 자식 컴포넌트 전체 코드
더보기// src/components/fragments/ProvideInject.vue <template> <div> <provide-inject /> </div> </template> <script> import ProvideInject from '@/components/fragments/ProvideInject.vue' export default { components: { 'provide-inject': ProvideInject }, data() { return { sampleData: 'AAA' } }, provide() { return { size: 5, str: this.sampleData } } } </script>
728x90반응형'영광의 시대! > 2022 개발자의 품격 부트캠프 1기' 카테고리의 다른 글
[개발자의품격][부트캠프][1기][22차시] Vue.js #11 | mixin, axios, 전역 처리 (0) 2022.03.15 [개발자의품격][부트캠프][1기][21차시] Vue.js #10 | 전역 컴포넌트, 커스텀 디렉티브 (0) 2022.03.15 [개발자의품격][부트캠프][1기][20차시][21차시] Vue.js #8 | Lifecycle Hooks (0) 2022.03.11 [개발자의품격][부트캠프][1기][20차시] Vue.js #7 | 재사용 컴퍼넌트에 checkbox, radio button, custom event 적용 등 (0) 2022.03.10 [개발자의품격][부트캠프][1기][19차시] Vue.js #6 | 재사용 컴퍼넌트에 부트스트랩 적용 (0) 2022.03.07 다음글이 없습니다.이전글이 없습니다.댓글