vue.js/Vue3 - 기본편

24. Provide / Inject

DEV-Front 2024. 2. 11. 21:06
반응형

 

부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달할때 Props를 사용해서 데이터를 전달했다.

 

 

그런데 전달해야 하는 Props의 길이가 깊다면?

그것도 깊이가 아주 깊다면?

이런 경우에는 모든 컴포넌트 사이에 Props를 전달 해야함으로 굉장히 번거롭다.

중간에 있는 컴포넌트는 단순히 하위 컴포넌트에 데이터를 전달하기 위해 Props를 선언해야 한다. 

 

 

이렇게 하위 컴포넌트를 단순히 Props를 전달하기 위한 컴포넌트로 쓰는걸 Prop Drilling 이라고 한다.

이런 문제를 해결할수 있는것이 바로 Provide와 Inject다. 

이걸 사용하면 계층구조의 깊이에 상관없이 모든 자식 컴포넌트에 데이터를 전달 할 수 있다.

 


Prop Drilling

 

일반적을 부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달해야 할 때 props를 사용합니다. 하지만 규모가 큰 컴포넌트 트리가 있고 깊이 중첩된 자손 컴포넌트에 데이터를 전달해야 한다면 해당 자손 컴포넌트와 연관된 모든 자식 컨포넌트에게 동일한 prop을 전달해야 합니다

<Root>에서 <DeepChild> 컴포넌트에 데이터를 전달하기 위해서는 <Footer> 컴포넌트를 거쳐 데이터를 전달해야 합니. 만약 더 긴 상위 체인이 있으면 더 많은 상위 컴포넌트들이 영향을 받습니다. 이것을 “Prop Drilling”이라고 합니다.

 

“Prop Drilling” 문제는 Vue3의 provideinject로 해결할 수 있습니다. provideinject를 사용하면 데이터를 제공하는 상위 컴포넌트는 dependency provider 역할을 합니다. 그리고 데이터를 받는 하위 컴포넌트는 깊이에 관계 없이 dependency provider가 제공하는 종속성(data, function 등)을 주입받을 수 있습니다.

Provide

 

하위 컴포넌트 항목에 데이터를 제공하려면 provider 역할을 하는 상위 컴포넌트 setup()함수 내부에서 provide()를

사용하여 데이터를 제공할 수 있습니다.

import { provide } from 'vue';

export default {
  setup() {
    provide('message', 'hello!');
  },
};

 

provide() 함수는 두개의 파라미터를 받습니다.

  • 첫번째 파라미터는 주입 키 : 문자열 또는 symbol이 될 수 있습니다. 주입 키는 하위 컴포넌트에서 주입된 값을 조회하는데 사용됩니다.
  • 두번째 파라미터는 제공된 값 : 값은 refs와 같은 반응성 데이터를 포함하여 모든 유형이 될 수 있습니다

 

 

import { provide, ref } from 'vue';

export default {
  setup() {
    const message = ref('Hello World!');
    provide('message', message);
    return {
      message,
    };
  },
}

반응성 데이터를 사용함녀 제공된 값을 사용하는 하위 컴포넌트가 공급자 컴포넌트에 대한 반응연결을 설정할 수 있습니다.


Inject

상위 컴포넌트에서 제공한 데이터를 삽입하려면 하위 컴포넌트 setup()함수 내부에서 inject() 함수를 사용할 수 있습니다.

import { inject } from 'vue';
export default {
  setup() {
    const message = inject('message');
    const appMessage = inject('appMessage');
    return {
      message,
      appMessage,
    };
  },
};

 

주입된 값이 ref면 반응성 연결을 유지할 수 있습니다.


Injection 기본 값

 

만약에 inject로 주입된 키가 상위 체인 어디에서든 제공되지 않을경우 런타임 경고 표시됩니다.

이때 두번째 인자로 기본값(Default Value)를 설정할 수 있습니다.

const defaultMessage = inject('defaultMessage', 'default message');

 

기본값으로 팩토리함수를 제공할 수도 있습니다.

const defaultMessage = inject('defaultMessage', () => 'default message');

Reactivity

 

Provide/Inject를 반응성 데이터로 제공할 때 가능한 모든 변경을 Provider 내부에서 하는 것이 좋습니다. 이렇게 Provider 내부에 배치되면 향후 유지관리가 용이합니다.
(데이터를 자식 컴포넌트에서 바꿀수 없게, 부모 컴포넌트에서 데이터 변경 메서드도 같이 제공하란 뜻)
만약에 injector 내부 컴포넌트에서 반응성 데이터를 변경해야 하는 경우 데이터 변경을 제공하는 함수를 함께 제공하는 것이 좋습니다
// Provider
const message = ref('Hello World!');
const updateMessage = () => {
  message.value = 'world!';
};
provide('message', { message, updateMessage });
// Injector
const { message, updateMessage } = inject('message');

그리고 주입된 컴포넌트에서 제공된 값을 변경할 수 없도록 하려면 readonly() 함수를 사용할 수 있습니다.

import { provide, readonly, ref } from 'vue';

provide('count', readonly(count));

Symbol 키 사용

 

대규모 애플리케이션에서 다른 개발자와 함께 작업할 때 잠재적 충돌을 피하기 위해 Symbol 주입 키를 사용하는 것이 가장 좋습니다.

// keys.js
export const myInjectionKey = Symbol()
// in provider component
import { provide } from 'vue'
import { myInjectionKey } from './keys.js'

provide(myInjectionKey, {
  /* data to provide */
})
// in injector component
import { inject } from 'vue'
import { myInjectionKey } from './keys.js'

const injected = inject(myInjectionKey)

App-level Provide

컴포넌트에서 데이터를 제공하는 것 외에도 App-level에서 제공할 수도 있습니다.

import { createApp } from 'vue';
import App from './App.vue';
const app = createApp(App);
app.provide('appMessage', 'Hello app message');
app.mount('#app');

Provide/Inject 사용 예

App-level에서의 Provide는 앱에서 렌더링되는 모든 컴포넌트에서 사용할 수 있습니다. 이것은 Plugin을 작성할 때 유용합니다.
Vue2에서 컴포넌트 인스턴스 객체를 추가할 때 global property에 추가 했으나, Vue3에서 Composition API Setup 함수에서는 컴포넌트 인스턴스에 접근할 수 없다.
이때 대신 Provide/Inject를 사용할 수 있다.

 

 

참고

https://vuejs.org/api/application.html#app-config-globalproperties

 

Vue.js

Vue.js - The Progressive JavaScript Framework

vuejs.org


app.config.globalProperties

globalProperties는 애플리케이션 내부의 모든 구성 요소 인스턴스에서 액세스할 수 있는 전역 속성을 등록하는 데 사용할 수 있는

개체입니다.  globalProperties에 데이터를 넣으면 컴포넌트 인스턴스에서 데이터를 사용할 수 있습니다.

 

컴포넌트 인스턴스는 this로 접근합니다.

mounted 라이프 사이클 훅은 컴포넌트 인스턴스가 생성 된 후 기 때문에 this로 접근할 수 있습니다.

하지만, Vue3의 CompositionAPI의 setUp()함수 에서는, 컴포넌트 인스턴스가  생성되기 전이기 때문에 this로 접근할 수 없습니다.

 

이럴때 Provide와 Inject를 활용할 수 있습니다.

app.config.globalProperties 대신 app.provide('msg', 'hello msg'); 로 제공하는것 입니다.

그러면 setUp()함수 안에 Inject로 데이터 주입이 가능해집니다.

그렇기 때문에 모든 컴포넌트에서 사용하는 라이브러리가 있다면 이렇게 Provide하는것도 좋습니다.

반응형

'vue.js > Vue3 - 기본편' 카테고리의 다른 글

25. Lifecycle Hooks  (0) 2024.02.12
23. Slot  (0) 2024.02.05
22. Non-Prop 속성 (fallthrough 속성)  (0) 2024.02.04
21. Events  (0) 2024.02.04
20. Props  (0) 2024.01.29