Vue3

provide/inject

덕구공 2022. 10. 21. 14:54

provide/inject

  • Vue.js에서 전역 상태를 사용해서 prop drilling을 피할 수 있는 방법이다!
  • 전역 상태를 넘길수 있는 방법이 크게? 두가지가 있다. reactive한 상태를 넘기는 것과 그렇지 않은 상태를 넘기는 것!
  • 사용법은 전역 상태를 넘길 컴포넌트에서 provide 키워드를 사용해서 전역 상태를 넘기고 자식이나 자손들이 inject 키워를 이용해 해당 상태를 사용하는 방식이다!

reactive 하지 않은 상태

  • proivde로 넘겨준 상태가 변경되도 자식이나 후손이 리렌더링 되지 않는 경우!
  • 별다른 키워드 없이 최상위 컴포넌트에서 provide 키워드 안에 computed를 사용하지 않고 상태를 전달하는 경우!

 

최상위 컴포넌트

  • provide 키워드를 사용해서 num이라는 전역 상태를 넘겨준다.
  • 자신이 직접 이 상태를 사용할 땐 undefined 값이 나온다
<template>
  <!-- provide를 사용한 컴포넌트에선 template에 provide로 넘긴 state 사용 안됨 -->
  <h1>global num: {{ num }}</h1>
  <h1>I'm Father</h1>
  <ProvideChild />
</template>

<script>
import ProvideChild from "./components/ProvideChild.vue";
export default {
  components: { ProvideChild },
  name: "App",
  provide() {
    return {
      num: 1,
    };
  },
  mounted() {
    // undefined -> provide를 넘겨주는 컴포넌트는 해당 state에 접근 불가 ?
    // 확인 더 해봐야 할듯;
    console.log(this.num);
  },
};
</script>

자식 컴포넌트

  • inject로 최상위 컴포넌트가 넘겨준 전역 state를 받아와서 화면에 나타냄과 동시에 값을 1 증가시키는 버튼을 가지고 있다.
  • 버튼을 클릭해서 값을 증가시켜도 화면에 나타나는 num은 변하지 않는다..!
<template>
  <h2>I'm Child, global num = {{ num }}</h2>
  <button @click="add_one">num++ from Child</button>
  <ProvideGrandson />
</template>

<script>
import ProvideGrandson from "./ProvideGrandson.vue";
export default {
  components: { ProvideGrandson },
  inject: ["num"],
  methods: {
    add_one() {
      this.num++;
      console.log(this.num);
    },
  },
};
</script>

손자 컴포넌트

  • 자식 컴포넌트와 마찬가지로 inject로 최상위 컴포넌트가 넘겨준 전역 state를 받아와서 화면에 나타냄과 동시에 값을 1 증가시키는 버튼을 가지고 있다.
  • 버튼을 클릭해서 값을 증가시켜도 화면에 나타나는 num은 변하지 않는다..!
  • 또한 자식 컴포넌트와 같은 값을 inject를 해도 두 값이 다르다!
    • 예를 들어 자식 컴포넌트에서 1 증가시켜서 2가 된다고 해도 손자는 1
    • 단지 초기값이기 때문!!
<template>
  <h2>I'm Grandson, global num = {{ num }}</h2>
  <button @click="add_one">num++ from GrandSon</button>
</template>

<script>
export default {
  inject: ["num"],
  methods: {
    add_one() {
      this.num++;
      console.log(this.num);
    },
  },
};
</script>

실행 예시

  • 자식이나 자손 컴포넌트가 provide로 넘긴 전역 상태를 inject로 받아서 값을 변경해도 view에는 적용되지 않는다!!
    • console에는 값이 변화한 것으로 나타나긴한다
  • 즉, reacitve 하지 않은 상태를 넘겨주면 그 값을 바꾸려고 하지 말자!


reactive 한 상태

  • provide한 상태가 변경되면 자식과 후손들이 렌더링 되는 상태
  • 상태를 provide하는 최상위 컴포넌트에서 data 속성에 있는 값을 computed 키워드와 함께 provide하면 이 전역 상태는 reactive한 상태가 된다!

최상위 컴포넌트

  • data 속성에 있는 reacitve한 값을 computed를 arrow function과 함께 사용해서 provide에 넣어준다.
  • 또한 자신의 상태를 바꾸는 함수를 provide 안의 arrow function으로 넣어주거나 methods 속성에 따로 선언해야 한다!
    • provide의 this는 inject를 사용하는 자식이나 손자가 되는 것 같다!
<template>
  <h1>global num: {{ number }}</h1>
  <h1>I'm Father</h1>
  <ProvideChild />
</template>

<script>
import { computed } from "@vue/runtime-core";
import ProvideChild from "./components/ProvideChild.vue";
export default {
  components: { ProvideChild },
  name: "App",
  data() {
    return {
      number: 1,
    };
  },
  provide() {
    return {
      num: computed(() => this.number),
      add_one: () => {
        this.number++;
        console.log(this.number);
      },
    };
  },
};
</script>

자식 컴포넌트

  • 전역 상태를 inject하고 값을 1 증가시키는 버튼을 가지고있다
<template>
  <h2>I'm Child, global num = {{ num }}</h2>
  <button @click="add_one">num++ from Child</button>
  <ProvideGrandson />
</template>

<script>
import ProvideGrandson from "./ProvideGrandson.vue";
export default {
  components: { ProvideGrandson },
  inject: ["num", "add_one"],
};
</script>

손자 컴포넌트

  • 자식 컴포넌트와 마찬가지로 전역 상태를 inject하고 값을 1 증가시키는 버튼을 가지고있다
<template>
  <h2>I'm Grandson, global num = {{ num }}</h2>
  <button @click="add_one">num++ from GrandSon</button>
</template>

<script>
export default {
  inject: ["num", "add_one"],
};
</script>