[Vue.js] Provide / Inject 자식의 자식의...n에게 데이터 전달하기

토끼는 개발개발·2023년 11월 1일
0

Vue.js

목록 보기
17/19
post-thumbnail

📌 1. Provide / Inject

1) Provide와 Inject란?

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

그런데 위와 같이 Props의 깊이가 깊다고 가정해보자.
그것도 아주 많이 깊다고 가정해보면, 계속해서 Props로 전달하는 것은 굉장히 불편할 것이다. 중간에 있는 컴포넌트들은 그저 Props를 전달하기 위해 선언해야 할 것이다.
이렇게 하위 컴포넌트들이 전달하는 용도로만 쓰이는 과정을 Prop Drilling이라고 한다.

이것을 해결할 수 있는 것이 바로 Provide와 Inject이다.

Provide와 Inject를 사용하면, 부모 컴포넌트는 계층구조에 상관없이 자식 컴포넌트에 데이터를 전달할 수 있다.




2. Provide / Inject 사용법

(1) Provide

import { provide, ref } from 'vue';

export default {
  setup() {
    const message = ref('Hello World!');
    provide('message', message);
    return {
      message,
    };
  },
};
  • 첫 번째 파라미터(주입할 키): 문자열 또는 Symbol. 주입 키는 하위 컴포넌트에서 주입된 값을 조회하는 데 사용된다.
  • 두 번째 파라미터(주입할 값): 값은 refs와 같은 반응형 데이터를 포함하여 모든 유형이 될 수 있다.

(2) Inject

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

Inject를 통해 상위 컴포넌트에서 제공한 데이터를 삽입할 수 있다.
주입된 값이 ref이면 반응형 연결을 유지할 수 있다.

만약에 Inject로 주입된 키가 상위 체인에서 제공된 적이 없는 경우 런타임 경고가 표시된다. 이 때 두번째 인자로 기본값(default value)를 설정할 수 있다.

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

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

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



3. 반응형 데이터 제공시 주의점

Provide/Inject를 반응성 데이터로 제공할 때 가능한 모든 변경을 Provider 내부에서 하는 것이 좋다. 예를 들면 자식 컴포넌트에서 주입받은 값을 변경하고 싶으면, Injector 내부 컴포넌트에서 변경하지 말고 Provider에서 데이터 변경 함수를 함께 제공하는 것이 좋다.

// Provider
const message = ref('Hello World!');
const updateMessage = () => {
  message.value = 'world!';
};
provide('message', { message, updateMessage });
// Injector
const { message, updateMessage } = inject('message');

이렇게 Provider 내부에 배치되면 향후 유지관리가 용이하다.

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

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

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

4. 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)


5. App-level Provide

컴포넌트에서 데이터를 제공하는 것 외에도 App-level에서 제공할 수도 있다.
App컴포넌트는 모든 자식 컴포넌트의 부모 컴포넌트이므로 App-level에서 제공하면 모든 컴포넌트에서 받아 쓸 수 있다.

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

이것은 Plugin을 작성할 때 유용하다.
Vue2에서 컴포넌트 인스턴스 객체를 추가할 때 global property에 추가 했으나, Vue3에서 Composition API Setup 함수에서는 컴포넌트 인스턴스에 접근할 수 없다.

이때 대신 Provide/Inject를 사용할 수 있다.




참고문헌

vue공식문서 Provide/Inject
인프런 Vue3기본편 - 짐코딩

profile
하이 이것은 나의 깨지고 부서지는 샏 스토리입니다

0개의 댓글