코드를 통과해야하는 문제를 해결하는데 Vue를 어떻게 사용할 수 있을까?
다시 말하면, props와 커스텀 이벤트가 여러 컴포넌트를 통과하는게 꼭 문제인건 아니다. 기존 방식대로 해도 괜찮다.
하지만 불필요한 코드를 작성하지 않으려면 새로운 방법이 좋다.
# props 대신 provide - inject 사용
먼저 props인 topics부터 시작해보자.
KnowledgeGrid.vue에 topics를 다른 방법으로 전달해보자.
topics가 KnowledgeGrid.vue에 필요하고, App.vue에서 관리해야한다.
App.vue는 topics가 필요한 ActiveElement 컴포넌트도 있고, KnowledgeBase도 있고, 이 KnowledgeBase 컴포넌트는 마지막에 KnowledgeGrid.vue이 연결된다.
topics를 KnowledgeBase를 통해 전달하지 않는다면, App.vue에서 topics가 필요한 KnowledgeGrid.vue에 어떻게 전달할 수 있을까?
Vue가 제공하는 또 다른 기능 → provide와 inject.
한 곳에 데이터를 provide하고 inject, 즉 해당 데이터를 다른 곳에서 사용하는데 이용할 수 있는 패턴이다.
// App.vue
provide: {
topics: [
{
id: 'basics',
title: 'The Basics',
description: 'Core Vue basics you have to know',
fullText:
'Vue is a great framework and it has a couple of key concepts: Data binding, events, components and reactivity - that should tell you something!',
},
{
id: 'components',
title: 'Components',
description:
'Components are a core concept for building Vue UIs and apps',
fullText:
'With components, you can split logic (and markup) into separate building blocks and then combine those building blocks (and re-use them) to build powerful user interfaces.',
},
],
},
App.vue에 topics를 provide 할 수 있다.
1/ config 객체 내에 아무곳에 provide 옵션을 추가해라. provide는 객체를 취할 수 있고, 여기에 topics를 제공할 수 있다.
topics 배열을 가져와서 provide 옵션에 입력한다.
2/ topics를 사용할 컴포넌트에 inject를 추가하자.
이렇게 provide된 데이터를 어딘가에서 사용해야한다.
이 경우엔 KnowledgeGrid.vue에서 topics가 필요하다.
이 작업을 위해 topics를 props로 가져오는 대신, 다른 옵션을 추가할 예정이다. 바로 provide와 함께 작동하는 inject 옵션.
inject는 기본적으로 props와 동일하게 작동한다. 배열을 제공하고, 컴포넌트에서 사용하고 싶은 모든 제공된 데이터를 참조할 수 있다.
<script>
export default {
inject: ['topics'],
};
</script>
## provide-inject 사용 시 주의할 점
여기서 한가지 중요한 점이 있다.
바로, 상위 레벨에서 provide한 것만 inject할 수 있다. 즉, KnowledgeGrid.vue 컴포넌트의 부모 컴포넌트, 조상컴포넌트가 provide한 것만 inject할 수 있다.
App.vue 컴포넌트는 KnowledgeGrid.vue의 상위에 있으므로 inject할 수 있다.
ActiveElement.vue에서 provide된 것은 KnowledgeGrid.vue에서 inject할 수 없다. 왜냐하면, ActiveElement.vue는 KnowledgeBase.vue의 이웃이고, KnowledgeGrid.vue는 KnowledgeBase.vue에 포함되어 있다. 최종적으로 ActiveElement는 KnowledgeGrid의 이웃이다. 그래서 작동하지 않는다.
provide-inject 관계는 부모-자식 관계여야 한다. 이웃간에는 provide-inject가 불가능하다.
저장하면 이전과 동일하게 작동한다. 하지만 KnowledgeBase.vue에 topics가 통과하지 않아도 된다. 확실히 개선되었다.
## data 프로퍼티를 provide 하려면?
하지만, 문제가 하나 있다. 바로, topics 배열을 두 번 생성했다.
App.vue 내에 topics 배열이 하나 있고, provide 객체에도 있다. 이 경우엔 작동하긴 하지만 코드 중복이다.
(아래 코드를 보면, topics 배열만 두 번 적혀있다. 코드중복이다.)
App.vue
<script>
export default {
data() {
return {
topics: [
{
id: 'basics',
title: 'The Basics',
description: 'Core Vue basics you have to know',
fullText:
'Vue is a great framework and it has a couple of key concepts: Data binding, events, components and reactivity - that should tell you something!',
},
{
id: 'components',
title: 'Components',
description:
'Components are a core concept for building Vue UIs and apps',
fullText:
'With components, you can split logic (and markup) into separate building blocks and then combine those building blocks (and re-use them) to build powerful user interfaces.',
},
],
activeTopic: null,
};
},
provide: {
topics: [
{
id: 'basics',
title: 'The Basics',
description: 'Core Vue basics you have to know',
fullText:
'Vue is a great framework and it has a couple of key concepts: Data binding, events, components and reactivity - that should tell you something!',
},
{
id: 'components',
title: 'Components',
description:
'Components are a core concept for building Vue UIs and apps',
fullText:
'With components, you can split logic (and markup) into separate building blocks and then combine those building blocks (and re-use them) to build powerful user interfaces.',
},
],
},
};
</script>
만약 data에 저장된 topics 배열을 변경하는 로직이 앱 내에 있다면, provide 객체 내의 topics는 변경사항이 반영되지 않는다. 메모리에서는 data의 topics 배열과 provide 객체 내의 topics는 전혀 다른, 새로운 객체이다. 그래서 data에 있는 원래 배열을 변경하면 provide의 topics에 의존하는 컴포넌트에는 변경사항이 전달되지 않는다.
data의 topics를 provide하여 최종 변경사항이 반영되도록 하는 것이 더 좋다.
우선 provide를 사용하는 방법을 변경해야한다. provide를 데이터가 있는 객체로 설정하는 대신, provide를 method로 전환한다.
그러면 provide 옵션은 함수를 가지게 된다. 여기에 provide 객체를 반환한다. data 옵션처럼 작동한다.
이젠 this 키워드를 사용해서 특정 인스턴스 데이터에 접근할 수 있다.
이제 this.topics로 data 옵션의 topics에 접근한다.
provide(){
return {
topics: this.topics //지금은 같지만, 여기 사용한 key는 data에 있는 key와 같은 이름일 필요는 없다.
}
}
이와 같이 변경하면 잘 작동한다. 지금은 메모리에 있는 같은 객체로 작업하고 있다.
실제 잘 작동하는지 보기 위해, data에 있는 topics를 변경하여 시뮬레이션해보자.
mounted 훅을 추가해보자.
mounted(){
setTimeout(() => {
this.topics.push({
id: 'events',
title: 'Events',
description: 'Events are important in Vue',
fullText: 'Events allow you to trigger code on demand'
})
}, 3000)
} // 이 topic은 Vue앱이 화면에 렌더링 된 후, 3초가 지나면 추가된다.
3초 후에 이 topic도 추가되어 아래와 같이 화면에 출력된다.
만약 data의 topics를 provide하지 않았더라면 3초가 지나도 topic이 추가된 화면이 구현되지 않는다.
이것으로 provide, inject가 잘 작동된다는걸 확인했다.
provide, inject는 props, 컴포넌트를 불필요하게 통과하는 것을 피하는데 아주 유용한 패턴이다.
** 출처: 모든 내용은 Udemy Vue-완벽가이드 강의를 기반으로 작성하였습니다.
'Vue.js' 카테고리의 다른 글
[Udemy Vue 완벽가이드 Section8] 106. provide + inject vs props 및 커스텀 이벤트 (0) | 2023.08.28 |
---|---|
[Udemy Vue 완벽가이드 Section8] 105. 함수/메서드에서의 provide + inject (0) | 2023.08.28 |
[Udemy Vue 완벽가이드 Section8] 103. 잠재적인 문제점 (0) | 2023.08.27 |
[Udemy Vue 완벽가이드 Section8] 102. 데모: 더 많은 컴포넌트 통신 추가하기 (0) | 2023.08.27 |
[Udemy Vue 완벽가이드 Section8] 101. 데모: 컴포넌트 추가 및 연결하기 (0) | 2023.08.26 |