- 이번 포스팅에서 provide와 inject에 대해 알아볼 것이다.
1. 예제코드
[App.vue]
<template>
<Parent :msg="message" />
</template>
<script>
import Parent from '~/components/Parent'
export default {
components: {
Parent
},
data() {
return {
message: 'Hello, world!'
}
}
}
</script>
[Parent.vue - components 폴더 안에 생성]
<template>
<Child :msg="msg" />
</template>
<script>
import Child from '~/components/Child'
export default {
components: {
Child
},
props: {
msg: {
type: String,
default: ''
}
}
}
</script>
[Child.vue - components 폴더 안에 생성]
<template>
<div>
{{ msg }}
</div>
</template>
<script>
export default {
props: {
msg: {
type: String,
default: ''
}
}
}
</script>
[출력결과]
* props - 부모와 자식 컴포넌트 간의 데이터 통신을 가능하게 한다.
a) 코드의 흐름
- App.vue에서 Parent 컴포넌트를 출력한다.
- Parent 컴포넌트는 msg라는 props(속성)를 사용하는데, 이 props는 Child.vue에서 넘어온다.
- 그러므로 Parent 컴포넌트에서 Child.vue를 import한다.
- 결론적으로 화면에 출력되는 문구는 Child.vue에서 'msg'라는 부분인데, 이는 props를 통해 App.vue에서 Parent.vue를 거쳐온 데이터이다.
b) 코드의 효율성
- 위의 코드를 살펴보면 코드의 흐름이 효율적이지 않다는 것을 알 수 있다.
- App.vue에서 msg라는 객체를 사용하기 위해서 Parent.vue를 거쳐 Child.vue에 접근해야 하기 때문이다.
- 더불어, Parent.vue와 Child.vue는 msg라는 객체를 전달하는 것 외에는 구체적인 역할이 없다.
- 이처럼 데이터 활용의 불편함과 비효율성을 개선할 수 있는 방법이 Provide와 Inject다.
2. Provide & Inject
a) 예제코드
[App.vue]
<template>
<Parent />
</template>
<script>
import Parent from '~/components/Parent'
export default {
components: {
Parent
},
data() {
return {
message: 'Hello, world!'
}
},
provide() {
return {
msg: this.message
}
}
}
</script>
[Parent.vue]
<template>
<Child />
</template>
<script>
import Child from '~/components/Child'
export default {
components: {
Child
},
}
</script>
[Child.vue]
<template>
<div>
Child.vue: {{ msg }}
</div>
</template>
<script>
export default {
inject: ['msg']
}
</script>
[출력화면]
b) 코드의 흐름
- Provide와 Inject 사용을 통해 App.vue에서 props와 v-bind 없이 Child.vue에 접근할 수 잇게 되었다.
- 다시 말해, 굳이 Parent.vue를 거치지 않아도 App.vue에서 직접적으로 Child.vue의 msg속성에 접근할 수 있게 된 것이다.
3. 주의사항
a) Provide는 반응성을 제공하지 않는다.
[App.vue]
<template>
<button @click="message = 'Good?'">
Click
</button>
<h1>App.vue: {{ message }} </h1>
<Parent />
</template>
<script>
import Parent from '~/components/Parent'
export default {
components: {
Parent
},
data() {
return {
message: 'Hello, world!'
}
},
provide() {
return {
msg: this.message
}
}
}
</script>
[출력화면]
b) 코드해설
- 버튼과 h1 태그를 이용하여 버튼을 누르면 h1 태그의 message가 Good?으로 변경되도록 만들었다.
- 분명히 Child.vue의 template 부분에 작성된 {{ msg }} 에는 App.vue에서 설정한 message 객체의 내용(= Hello, world!)을 출력한다. 하지만, 위의 예제에서는 버튼을 클릭하더라도 Child.vue 의 {{ msg }} 내용이 변하지 않는 것을 확인할 수 있다. 이상하지 않은가?
- 결론적으로, provide와 inject를 사용하는 경우 반응성이 지원되지 않기 때문에 이와 같은 상황이 발생하는 것이다.
- 그러므로 provide와 inject를 사용한다면, 변동성이 없는 데이터를 출력하기 위한 용도로 사용하는 것이 적절하다.
- 그러나, 반응성을 만들어 줄 수 있는 방법이 있다.
4. Provide와 Inject 반응성 만들기
[App.vue]
<template>
<button @click="message = 'Good?'">
Click
</button>
<h1>App.vue: {{ message }} </h1>
<Parent />
</template>
<script>
import Parent from '~/components/Parent'
import { computed } from 'vue'
export default {
components: {
Parent
},
data() {
return {
message: 'Hello, world!'
}
},
provide() {
return {
msg: computed(() => this.message)
}
}
}
</script>
[Child.vue]
<template>
<div>
Child.vue: {{ msg.value }}
</div>
</template>
<script>
export default {
inject: ['msg']
}
</script>
[출력화면]
a) 코드해설
- computed는 어떤 변수 값의 변동을 추적하는 기능이다.
- 반응성이 없는 provide에서 반응성을 만들어주기 위해 computed를 속성이 아니라 메소드 형태로 사용해주었다.
- 이로써 App.vue의 message 변수의 값이 변하게 되면 msg 또한 변하도록 변동성을 부여하게 된 것이다.
5. 복습
- 프로젝트의 구조를 보면 App.vue는 Parent.vue의 부모 컴포넌트다.
- Parent.vue는 Child.vue의 부모 컴포넌트다. 고로, App.vue는 부모의 부모 컴포넌트가 되는 것이다.
- 일반적으로 부모의 부모 컴포넌트가 되는 대상을 상위 컴포넌트 또는 조상 컴포넌트라고 부른다.
- 조상 컴포넌트에서 자식컴포넌트로(App.vue → Parent.vue) 데이터를 전달할 때에는 props를 사용할 수 있었다.
- 하지만, 조상 컴포넌트에서 후손 컴포넌트로(App.vue → Child.vue) 데이터를 전달하는 경우 맨 처음의 예제코드처럼 Parent.vue와 같은 매개체 역할을 하는 컴포넌트를 필요로 한다.
- 이 매개체 역할을 생략하기 위한 방법이 바로 Provide와 Inject 이다.
- 하지만, Provide와 Inject를 이용하여 조상 컴포넌트에서 후손 컴포넌트로 직접 데이터를 전달하게 되면 props와는 달리 반응성이 없다는 것이다.
- 반응성을 부여하기 위해 computed() 메소드를 활용하여 Provide & Inject에게 반응성을 부여하였다.
- 이로써 조상 컴포넌트에서 후손 컴포넌트로 직접 데이터를 전달 및 갱신할 수 있는 구조를 갖게 되었다.
'Front-end > Vue3' 카테고리의 다른 글
27. Vue - 컴포지션 API란? (2) | 2021.05.28 |
---|---|
26. Vue - 컴포넌트 Refs (0) | 2021.05.28 |
24. Vue - slot 태그 (0) | 2021.05.25 |
23. Vue- Emit(2) (0) | 2021.05.24 |
22. Vue - Emit(1) (0) | 2021.05.24 |
댓글