Posis

[Vue.js] Provide/inject를 활용한 컴포넌트 데이터 전달 본문

Vue.js

[Vue.js] Provide/inject를 활용한 컴포넌트 데이터 전달

CooNiHong 2021. 8. 15. 17:28

이번 포스트는 Provide/inject를 활용한 컴포넌트 데이터 전달에 대해서 다뤄보겠습니다.

props와 provide/inject

컴포넌트 간에 데이터 전달에는 props와 provide/inject 두 가지가 존재합니다.

  • props: 컴포넌트 태그마다 작성을 해서 데이터를 보내서 자식 컴포넌트 안에서 script안에 props를 정의해 주어야 합니다. 단, 컴포넌트를 여러 번 거친다고 할 때 모든 컴포넌트마다 작성을 해 주어야 합니다.

  • provide/inject: provide와 inject는 컴포넌트 태그에 작성하지 않습니다. script안에 작성하며 props와 다른 점은 컴포넌트가 여러 번 거쳐도 최상위 컴포넌트와 최하위 컴포넌트 단 두 곳에서만 작성하면 데이터 전달이 이루어집니다.

출처: Vue.js 공식문서, Provide/inject

props로 데이터 전달하기

<!-- App.vue -->
<template>
  <Component1 :msg="message" />
</template>

<script>
import Component1 from './components/Component1.vue';

export default {
  name: 'App',
  components: {
    Component1,
  },
  data() {
    return {
      message: 'Hello Vue.js!!',
    };
  },
};
</script>

<style></style>

<!-- Component1.vue -->
<template>
  <Component2 :msg="msg" />
</template>

<script>
import Component2 from './Component2.vue';

export default {
  components: {
    Component2,
  },
  props: {
    msg: {
      type: String,
      default: '',
    },
  },
};
</script>

<!-- Component2.vue -->
<template>
  <Component3 :msg="msg" />
</template>

<script>
import Component3 from './Component3.vue';

export default {
  components: {
    Component3,
  },
  props: {
    msg: {
      type: String,
      default: '',
    },
  },
};
</script>

<!-- Component3.vue -->
<template>
  <h1>{{ msg }}</h1>
</template>

<script>
export default {
  props: {
    msg: {
      type: String,
      default: '',
    },
  },
};
</script>

위에 코드는 다음과 같은 형태를 지니고 있습니다. 코드는 자세하게 볼 필요는 없습니다. 봐야 할 부분은 컴포넌트마다 script안에 props를 정의했다는 사실만 인지하면 됩니다. 하지만 컴포넌트가 이번 예제보다 더 깊어질수록 매번 작성해야 하는 코드 때문에 길이도 길어질 뿐만 아니라 힘들어집니다. 이를 해결하기 위해 provide/inject를 사용하는 것입니다.

provide/inject로 데이터 전달하기

<!-- App.vue -->
<template>
  <Component1 />
</template>

<script>
import Component1 from './components/Component1.vue';

export default {
  name: 'App',
  components: {
    Component1,
  },
  data() {
    return {
      message: 'Hi Vue.js!!',
    };
  },
  provide() {
    return {
      msg: this.message,
    };
  },
};
</script>

<style></style>

<!-- Component1.vue -->
<template>
  <Component2 />
</template>

<script>
import Component2 from './Component2.vue';

export default {
  components: {
    Component2,
  },
};
</script>

<!-- Component2.vue -->
<template>
  <Component3 />
</template>

<script>
import Component3 from './Component3.vue';

export default {
  components: {
    Component3,
  },
};
</script>

<!-- Component3.vue -->
<template>
  <h1>{{ msg }}</h1>
</template>

<script>
export default {
  inject: ['msg'],
};
</script>

provide/inject 예제 코드를 보시면 컴포넌트 태그 안에 props는 모두 지우고 script안에서만 작성하신 걸 보실 수 있습니다. 그것도 최상위 App.vue와 최하위 컴포넌트 Component3.vue에서만 작성했습니다.

provide의 코드는 data 코드와 비슷한 형식을 지니고 있습니다. 

provider() {
  return {

    inject에서 사용할 변수명: this.전달할 데이터 변수명

  }

}

inject는 배열 형식으로 작성되고 있습니다.

inject: ['msg']

 

이와 같이 컴포넌트가 여러 번 거치게 될 경우 props를 활용하는 것보다 provide/inject를 활용하는 것이 훨씬 편리할 수 있습니다.

 

provide 사용 시 주의사항

provide는 기본적으로 반응성을 제공해주지 않습니다. 그래서 이를 해결해주기 위해 computed를 활용하는 것입니다.

위 예제 코드에서 변경사항이 없는 코드는 생략하였습니다.

<!-- App.vue -->
<template>
  <button @click="message = 'Hi React'">Click!</button>
  <h1>App - {{ message }}</h1>
  <Component1 />
</template>

위 사진처럼 반응성을 제공해주지 않기 때문에 Component의 message는 변하지 않습니다.

<!-- App.vue -->
<template>
  <button @click="message = 'Hi React'">Click!</button>
  <h1>App - {{ message }}</h1>
  <Component1 />
</template>

<script>
import Component1 from './components/Component1.vue';
import { computed } from 'vue';

export default {
  name: 'App',
  components: {
    Component1,
  },
  data() {
    return {
      message: 'Hi Vue.js!!',
    };
  },
  provide() {
    return {
      msg: computed(() => this.message),
    };
  },
};
</script>

<style></style>

<!-- Component3 -->
<template>
  <h1>Component - {{ msg.value }}</h1>
</template>

<script>
export default {
  inject: ['msg'],
};
</script>

이처럼 provide안에 computed를 활용하여 데이터를 반환하고 최하위 컴포넌트에서 출력한 데이터뒤에 .value만 붙여주시면 반응성을 지닌 provide/inject를 사용하실 수 있습니다.

728x90