【Vue】provide/injectについて


# 目次
[1.はじめに](#1-はじめに)
[2.propsによるデータの受け渡し方法](#2-propsによるデータの受け渡し方法)
[3.provide/injectとは](#3-provide/injectとは)
[4.使い方](#4-使い方)
[5.まとめ](#5-まとめ)

---

## はじめに

この記事では、Vueの`provide/inject`について書いています。

--- 

## propsによるデータの受け渡し方法  
Vueでは、コンポーネント間のデータ渡しをするときは、`props`を使われるのが一般的です。  

---

親コンポーネントから子コンポーネントへpropsを受け渡すことで、コンポーネント間のデータの共有が可能です。  

コンポーネントの階層が深い場合に、propsを使うとバケツリレーのように各コンポーネントにprops定義が必要になります。  


---


<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397734/3e914b74-4267-a19b-ff1b-32635df7aaea.png">

---

親コンポーネントから孫コンポーネントへデータの共有をする場合は、**間の子コンポーネントでもpropsの定義が必要**になってしまい、vuex・piniaなどの状態管理の外部ライブラリが使われるケースがあります。　


---

## provide/injectとは


`provide/inject`を使うことで、propsを使わずにコンポーネント間のデータの共有が可能となります。  

親コンポーネントと孫コンポーネントでのみデータを共有したい場合に、**中間の子コンポーネントへのデータの注入・コード修正も不要**になります。  

---

<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397734/22a33225-cb69-7701-b3cb-128fd2320c43.png">

---

**親となるコンポーネントでprovide（共有したいデータの定義）を実装**し、**受け取りたいコンポーネント側でinject（共有データの注入）を実装**することで、コンポーネント間のデータ共有が可能になります。また、**propsのようなバケツリレー実装が防げます**。

> 引用元：https://v3.ja.vuejs.org/guide/component-provide-inject.html

---

## 使い方

今回は、**親コンポーネント**で定義したデータを**孫コンポーネント**に渡すコードを例に、`provide/inject`の使い方について解説します。


---

### ゴール

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397734/bf24205d-1a16-e2d2-8120-70f9a527da3c.png)

---

### 親コンポーネント（Parent.vue）の実装

`provide`を使用すると、任意の値をキー文字列と一緒に保持することができます。親コンポーネントで、`provide`を実装することで、その配下のコンポーネントでデータの注入（inject）が可能になります。  

※以降の実装では、styleタグの実装を省略している。

---

```vue
<template>
  <div class="box">
    <p>親コンポーネント： {{ name }}</p>
    <Child />
  </div>
</template>

<script>
import { provide, ref } from 'vue';
import Child from './Child.vue';

export default {
  name: 'Parent',
  components: {
    Child,
  },
  setup() {
    // 孫に渡したいデータ
    const name = ref('テスト太郎');
    // 第一引数：キーを指定
    // 第二引数：共有したいデータ
    provide('inputName', name);
    return {
      name,
    };
  },
};
</script>
```

---

### 子コンポーネント（Child.vue）の実装

子コンポーネントではデータを注入（inject）しないため、孫コンポーネントを表示するだけの実装になっています。

---

```vue
<template>
  <div class="box">
    <p>子コンポーネント</p>
    <GrandChild />
  </div>
</template>

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

export default {
  name: 'Child',
  components: {
    GrandChild,
  },
};
</script>
```
---

### 孫コンポーネント（GrandChild.vue）の実装

孫コンポーネントではデータを注入するため、`inject`を使用して共有データを参照しています。`inject`メソッドでは、**キーを引数に指定**することで、受け取りたいデータを特定し、参照することが可能です。  

今回の場合、親コンポーネントで、`inputName`をキーに指定しているため、inject時にも同様のキーを指定します。

---

```vue
<template>
  <div class="box">
    <p>孫コンポーネント： {{ name }}</p>
  </div>
</template>

<script>
import { inject } from 'vue';

export default {
  name: 'GrandChild',
  setup() {
    const name = inject('inputName');
    return {
      name,
    };
  },
};
</script>

```

---

以上で、親コンポーネント（Parent.vue）を表示すると、以下のように描画されます。  

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397734/bf24205d-1a16-e2d2-8120-70f9a527da3c.png)

---

## まとめ

- propsを使わなくても、コンポーネント間のデータの共有が可能
- `provide/inject`を使うとバケツリレーの実装が防げる
- `provide/inject`を多用しすぎると、コンポーネント間のデータの流れが複雑になりそう
  - ソースコードの可読性が低くなりそう
  - 使い所は慎重に判断した方が良い