본문 바로가기
Front-end/Vue3

25. Vue- provide, inject

by devraphy 2021. 5. 27.

- 이번 포스팅에서 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

댓글