Vuex を使うのに慣れすぎて、Vuex を使わないパターンを考えた時に色々考えたのでメモ
方針
- 比較的規模が小さいシステムでは、Vuex の利用をまずは避けたい
- Nuxt.js を使用
- Composition API を使用
コンポーネント間のデータ受け渡しパターン
親から子
- 普通に props 経由
子から親
$emit
で親の関数を呼ぶ.sync
修飾子と$emit.update
で親の状態を更新する
子から子
- 禁止
- 必ず親を経由する
親から親
たとえば、pages コンポーネントから pages コンポーネントにデータを渡したい時など
- EventBus で親子間以外のデータ受け渡しが行えるらしい
- ただし、現在は非推奨(公式でも Vuex を使った方がよいという見解)
- Vue3 では
$on
が削除される - Nuxt.js でも使えなくなるはず
代替手段
- URL に含めて vue-router から取る
- 渡したいデータが増えた時の拡張性が低い
- ブラウザのセッションストレージとかに入れとく
- なんか微妙(TypeScript 使っているし)
- Provide/Inject パターンを使う
- Vue の 2.2.0 からあるらしい
- Vuex の代わりになりそう
- これは小規模なアプリケーションには、よい気がする
Provide/Inject パターンの実装
Nuxt.js と Composition API での実装
Key/Value を定義する
Value にグローバルで管理したい状態とロジックを定義する
// composables/dashboard.ts import { Dashboard } from '@nuxt/types' import { ref, Ref, InjectionKey } from '@nuxtjs/composition-api' // Storeの型定義 export type DashboardStore = { dashboard: Ref<Dashboard> setDashboard: (d: Dashboard) => void } // Key export const DashboardKey: InjectionKey<DashboardStore> = Symbol( 'DashboardStore' ) // Value export const useDashboard = (): DashboardStore => { // 状態 const dashboard = ref<Dashboard>({ dashboard_id: 0, dashboard_name: '' }) // ロジック const setDashboard = (d: Dashboard) => (dashboard.value = d) return { dashboard, setDashboard } }
次に、上記の Key/Value で provide する
今回は pages コンポーネント間でデータ受け渡しを行いたいので、layout コンポーネントで実装した
// layouts/default.vue import { defineComponent, provide } from '@nuxtjs/composition-api' import { DashboardKey, useDashboard } from '@/composables/dashboard' export default defineComponent({ setup() { provide(DashboardKey, useDashboard()) } })
状態を変更する場合
// pages/set.vue import { defineComponent, inject } from '@nuxtjs/composition-api' import { DashboardKey, DashboardStore } from '@/composables/dashboard' export default defineComponent({ setup() { const { setDashboard } = inject<DashboardStore>(DashboardKey) || { setDashboard: () => console.error('Not found setDashboard') } setDashboard({...}) } })
状態を取得する場合
// pages/get.vue import { defineComponent, inject } from '@nuxtjs/composition-api' import { DashboardKey, DashboardStore } from '@/composables/dashboard' export default defineComponent({ setup() { const { dashboard } = inject<DashboardStore>(DashboardKey) || {} } })
データの種類と取得場所
静的なデータ
サーバーなどから 1 回取得したら、変更がないデータなど
「Nuxt の plugins で取得し、Nuxt のコンテキストに inject しておく」
- plugins 配下のスクリプトはルートの Vue コンポーネントがインスタンス化される前に実行される
- SSR していれば、クライアントとサーバーでそれぞれ実行される
nuxt.config.js
の plugins オプションで対象のモジュールを定義する際、mode
というオプションで、そのプラグインの実行をクライアントのみ、もしくは、サーバーのみと指定可能
これはいい感じな気がする
動的なデータ
たとえば、アプリケーション内で変更可能なデータなど
「親コンポーネントで状態を管理および、変更処理(サーバーからデータ取得など)を行う」
親コンポーネントが肥大化する場合
親コンポーネントが pages の場合