Vue.js におけるデータ共有の基本

# Vue.js におけるデータ共有の基本要件

### データ共有のために重要な2つの要件:

1. **リアクティブ性 (Reactivity)**:
   - データが変更された際に、コンポーネントが自動的に更新される必要がある。
   - 例えば、ユーザーの操作やバックエンドからのデータ更新があった場合、それに応じて画面が自動的に再描画される

2. **型安全性 (Type Safety)**:
   - データが型安全にやりとりされることが重要。
   - 特に大規模アプリケーションでは、正しいデータ型を維持することでバグを減らし、開発体験を向上させる。

---

# Vue.js 3 におけるデータ共有の4つの方法

## 1. Props を使う方法
### 概要
- 親コンポーネントから子コンポーネントにデータを渡すための最も基本的な方法。
- 子コンポーネントは親コンポーネントから `props` を受け取り、それを使ってデータを表示または操作する。

### サンプルコード
**親コンポーネント (Parent.vue):**
```vue
<template>
  <Child :message="greeting" />
</template>

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

export default {
  setup() {
    const greeting = 'こんにちは！';
    return { greeting };
  },
};
</script>

```

**子コンポーネント (Child.vue):**

```vue
<template>
  <div>{{ message }}</div>
</template>

<script>
export default {
  props: {
    message: String,
  },
};
</script>
```

### メリット
- シンプルで、親子関係の明示的なデータバインディングが可能。
- データの流れがわかりやすく、コンポーネント間の依存性が明確。

### デメリット
- 深いコンポーネント階層での使用には不向き（"props drilling" が発生しやすい）。

## 2. Provide / Inject + reactive を使う方法
### 概要
Provide で渡されるデータを ref にして、親からリアクティブに更新できる。

### サンプルコード
**親コンポーネント (Parent.vue):**

```vue
<template>
  <Child />
  <button @click="changeMessage">メッセージ変更</button>
</template>

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

export default {
  setup() {
    const message = ref('こんにちは！');
    provide('greeting', message);

    const changeMessage = () => {
      message.value = 'こんばんは！';
    };

    return { changeMessage };
  },
};
</script>

```

**子コンポーネント (Child.vue):**
```vue
<template>
  <div>{{ greeting }}</div>
</template>

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

export default {
  setup() {
    const greeting = inject('greeting');
    return { greeting };
  },
};
</script>

```

### メリット
- 親コンポーネントでデータが変更されたら、子コンポーネントにリアクティブに反映される。
- リアクティブな状態管理がシンプルに実現できる。
- データ子供の深くに渡せます
### デメリット
親子関係に依存するため、コンポーネントの階層が複雑になると管理が難しくなる。


## 3. グローバル ref を使う方法
### 概要
- Vue 3 の ref() を使って、どのコンポーネントでもアクセスできるグローバル変数を作る。

### サンプルコード
**store.js:**
```ts
import { ref } from 'vue';

export const globalCount = ref(0);

```

**任意のコンポーネント (ComponentA.vue):**
```vue
<template>
  <button @click="increment">増加</button>
</template>

<script>
import { globalCount } from './store.js';

export default {
  setup() {
    const increment = () => {
      globalCount.value++;
    };
    return { increment };
  },
};
</script>

```

### メリット
- 簡単にグローバルな状態管理ができる。
- リアクティブなデータバインディングが可能。

### デメリット
- データの管理が増えて、状態が増えると複雑になる。
- 大規模なアプリには不向き。

## 4. Pinia を使う方法

### 概要
- Vuex の代わりに使われる軽量なストアライブラリ。

### サンプルコード
**ストア (store.js):**
```ts
import { defineStore } from 'pinia';

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
  }),
  actions: {
    increment() {
      this.count++;
    },
  },
});

```

**任意のコンポーネント (ComponentA.vue):**
```vue
<template>
  <button @click="increment">増加</button>
</template>

<script>
import { useCounterStore } from './store.js';

export default {
  setup() {
    const store = useCounterStore();
    return { increment: store.increment };
  },
};
</script>

```

**別のコンポーネント (ComponentB.vue):**
```vue
<template>
  <p>カウント: {{ count }}</p>
</template>

<script>
import { useCounterStore } from './store.js';

export default {
  setup() {
    const store = useCounterStore();
    return { count: store.count };
  },
};
</script>

```

### メリット
- シンプル: 状態管理が簡潔で、直感的な API 。
- リアクティブ: 複数のコンポーネント間でリアクティブにデータを共有できる。
- 開発者ツール (Devtool) 対応: 状態の変化を Vue Devtools でデバッグできる。
- 型安全 (Typesafe): TypeScript に対応しており、型安全なストア管理が可能。
- モジュール化可能: 複数のストアを簡単に分けて管理できる。
### デメリット
- 小規模なプロジェクトには少しオーバーヘッドになる可能性がある。

## 結論: どの方法を使うべきか？ 
個人的に以下のこと
- propsは絶対に使う
- 親子関係が明確かつリアクティブな管理が必要: Provide / Inject + reactive
- 大規模なアプリじゃなければ: グローバルのref
- 大規模アプリや複雑な状態管理: Pinia