kurosame’s diary

フロントエンドが得意です

Nuxt.js で Vuex を使わない場合に考えること

Vuex を使うのに慣れすぎて、Vuex を使わないパターンを考えた時に色々考えたのでメモ

方針

  • 比較的規模が小さいシステムでは、Vuex の利用をまずは避けたい
  • Nuxt.js を使用
  • Composition API を使用

コンポーネント間のデータ受け渡しパターン

親から子

  • 普通に props 経由

子から親

  • $emitで親の関数を呼ぶ
  • .sync修飾子と$emit.updateで親の状態を更新する

子から子

  • 禁止
  • 必ず親を経由する

親から親

たとえば、pages コンポーネントから pages コンポーネントにデータを渡したい時など

代替手段

  • 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 の場合