0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Posted at

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

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

  1. リアクティブ性 (Reactivity):

    • データが変更された際に、コンポーネントが自動的に更新される必要がある。
    • 例えば、ユーザーの操作やバックエンドからのデータ更新があった場合、それに応じて画面が自動的に再描画される
  2. 型安全性 (Type Safety):

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

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

1. Props を使う方法

概要

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

サンプルコード

親コンポーネント (Parent.vue):

<template>
  <Child :message="greeting" />
</template>

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

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

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

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

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

メリット

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

デメリット

  • 深いコンポーネント階層での使用には不向き("props drilling" が発生しやすい)。

2. Provide / Inject + reactive を使う方法

概要

Provide で渡されるデータを ref にして、親からリアクティブに更新できる。

サンプルコード

親コンポーネント (Parent.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):

<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:

import { ref } from 'vue';

export const globalCount = ref(0);

任意のコンポーネント (ComponentA.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):

import { defineStore } from 'pinia';

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

任意のコンポーネント (ComponentA.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):

<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
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?