Vuexの新しいバージョンはどうなりますか?

Vuexは、Vueアプリケーションの状態マネージャーです。次のバージョンはVuex4で、正式リリースの準備がほぼ整っています。 Vue 3のサポートが追加されますが、新しい機能は提供されません。



Vuexは優れたソリューションと見なされており、多くの開発者がVuexを主要な状態管理ライブラリとして選択していますが、将来のリリースでより多くの機能を利用できるようになることを望んでいます。したがって、Vuex 4がリリースの準備をしている間、その開発者の1人である Kia King Ishii(コアチームの一部)は、次の5バージョンの計画すでに 共有しています。これらは単なる計画であり、いくつかのことが変更される可能性があることは注目に値しますが、それでも主な方向性はすでに選択されています。彼について議論されます。



Vue3とCompositionAPIの登場により 、開発者は単純な代替案を作成し始めました。たとえば、「おそらくVuexは必要ありません」という記事 は、CompositionAPIとを組み合わせてストアを作成するためのシンプルで柔軟かつ信頼性の高い方法を示しています provide/inject



。これと他のいくつかの代替手段は小さなアプリケーションには問題ないと想定できますが、よくあることですが、ドキュメント、コミュニティ、命名規則、統合、開発者ツールなどの欠点があります。







最後のポイントは非常に重要です。 Vueに優れた ブラウザ拡張機能が追加されました開発とデバッグを支援します。特に大規模なアプリケーションを構築する場合、それを捨てることは大きな損失になる可能性があります。幸い、これはVuex5では発生しません。代替アプローチに関しては、それらは機能しますが、公式の解決策ほど多くの利点をもたらすことはありません。したがって、彼らが私たちにどのような利点を約束するかを見てみましょう。



ストアの作成



サイドで何かをする前に、それを作成する必要があります。Vuex 4では、次のようになります。



import { createStore } from 'vuex'

export const counterStore = createStore({
  state: {
    count: 0
  },
  
  getters: {
    double (state) {
      return state.count * 2
    }
  },
  
  mutations: {
    increment (state) {
      state.count++
    }
  },
  
  actions: {
    increment (context) {
      context.commit('increment')
    }
  }
})

      
      





ストアも4つの部分で構成されています。データが保存される状態。計算された状態を提供するゲッター。ストアの操作を実行するためにストアの外部で呼び出される状態とアクションを変更するために必要なミューテーション。通常、アクションは(例のように)突然変異を引き起こすだけでなく、非同期タスクを実行するために(突然変異は同期でなければならないため)、またはより複雑なロジックを実装するために使用されます 。 Vuex 5はどのようになりますか?



import { defineStore } from 'vuex'

export const counterStore = defineStore({
  name: 'counter',
  
  state() {
    return { count: 0 }
  },
  
  getters: {
    double () {
      return this.count * 2
    }
  },
  
  actions: {
    increment () {
      this.count++
    }
  }
})

      
      





最初に変更されたのは、名前createStore



をに変更 すること defineStore



です。少し後に、その理由が明らかになります。次に、name



店舗名を指定するためのパラメータがありました 。その前に、側面をモジュールに分割し、モジュール名は名前付きオブジェクトの形式でした。さらに、モジュールはグローバルスペースに登録されていたため、モジュールは自給自足ではなく、再利用の準備ができていませんでした。解決策として、namespaced



複数のモジュールが同じタイプの変異とアクションに応答するのを防ぐために、パラメーターを使用する必要が ありました。多くの人がこれに出くわしたと思いますが、それでもドキュメントへのリンクを追加ます。現在、モジュールはありません。各ストアは、デフォルトで個別の独立したストレージです。



名前を指定state



したら、設定するだけでなく、初期状態を返す関数にする必要があり ます。これはdata



、コンポーネントでの外観と非常によく似てい ます。この変更は、データにアクセスするstate



ためのパラメーターとして関数使用する 代わりに、ゲッターにも影響を及ぼしました this



。同じアプローチが、パラメーターとしてではthis



なくアクション適用され stat



ます。最後に、そして最も重要なことに、突然変異はアクションゲームと組み合わされます。キアは 祝ったその突然変異は非常にしばしば単純なセッターになり、それらを冗長にします、明らかにこれが削除の理由でした。彼は、たとえばコンポーネントから、ストアの外部で状態を変更できるかどうかについては言及していません。ここでは、フラックスパターンのみを参照できます。これは、これを行うことを推奨せず、アクションから状態を変更するアプローチを推奨します。



補遺: Composition APIを使用してコンポーネントを作成する人は、同様の方法でストアを作成する方法があることを知って喜ぶでしょう。



import { ref, computed } from 'vue'
import { defineStore } from 'vuex'

export const counterStore = defineStore('counter', () => {
  const count = ref(0)

  const double = computed(() => count.value * 2)
  
  function increment () {
    count.value++
  }

  return { count, double, increment }  
})

      
      





上記の例では、最初の引数としてストア名を渡しました defineStore



残りは通常のCompositionAPIであり、結果は従来のAPIの例とまったく同じになります。



ストアの初期化



ここでは重要な変化が待っています。5番目のバージョンでストアの初期化がどのように行われるかを説明するために、4番目のバージョンでどのように行われるかを見てみましょう。を介してストアを作成する createStore



と、すぐに初期化され、でapp.use



または直接使用できるようになります



import { createApp } from 'vue'
import App from './App.vue'
import store from './store'

const app = createApp(App)

app.use(store)
app.mount('#app')

//        `this.$store`
//   `useStore()`   Composition API

import store from './store'

store.state.count // -> 0
store.commit('increment')
store.dispatch('increment')
store.getters.double // -> 4

      
      





5番目のバージョンでは、各Vuexインスタンスに個別にアクセスし、独立性を保証します。したがって、このプロセスは異なって見えます。



import { createApp } from 'vue'
import { createVuex } from 'vuex'
import App from './App.vue'

const app = createApp(App)
const vuex = createVuex()

app.use(vuex)
app.mount('#app')

      
      





すべてのコンポーネントは、グローバルスペースにアクセスする代わりに、任意のVuexインスタンスに直接アクセスできるようになりました。例を見てください:



import { defineComponent } from 'vue'
import store from './store'

export default defineComponent({
  name: 'App',

  computed: {
    counter () {
      return this.$vuex.store(store)
    }
  }
})

      
      





この呼び出し $vuex.store



により、ストアが作成および初期化されます(名前の変更について覚えておいてください createStore



)。これで、を介してこのリポジトリに通信するたび $vuex.store



に、作成済みのインスタンスが返されます。この例で this.counter



は、これをコードでさらに使用できます。を介してストアを初期化することもできます createVuex()







そしてもちろん、代わりに$vuex.store



使用される 、CompositionAPIのオプション useStore







import { defineComponent } from 'vue'
import { useStore } from 'vuex'
import store from './store'

export default defineComponent({
  setup () {
    const counter = useStore(store)

    return { counter }
  }
})

      
      





上記のアプローチ(コンポーネントを介してストアを初期化する)には、長所と短所の両方があります。一方では、これはコードの分離と、必要な場合にのみコードを追加する機能です。一方、依存関係を追加します(これで、ストアを使用するたびにストアをインポートする必要があります)。したがって、DIを使用する場合は、次を使用するオプション provide







import { createApp } from 'vue'
import { createVuex } from 'vuex'
import App from './App.vue'
import store from './store'

const app = createApp(App)
const vuex = createVuex()

app.use(vuex)
app.provide('name', store)
app.mount('#app')

      
      





そして、ストアをコンポーネントにスローします(name



定数に置き換えて、すでに使用したいという要望があり ます)。



import { defineComponent } from 'vue'

export default defineComponent({
  name: 'App',
  inject: ['name']
})

// Composition API

import { defineComponent, inject } from 'vue'

export default defineComponent({
  setup () {
    const store = inject('name')

    return { store }
  }
})

      
      





このソリューションにはそれほど興奮はありませんが、現在のアプローチよりも明確で柔軟に見えます。今後の使用についても同じことは言えません。これで、次のようになります。



store.state.count            // State
store.getters.double         // Getters
store.commit('increment')    // Mutations
store.dispatch('increment')  // Actions

      
      





新しいバージョンは次のことを期待されています:



store.count        // State
store.double       // Getters
store.increment()  // Actions

      
      





すべてのエンティティ(状態、ゲッター、およびアクション)に直接アクセスできるため、エンティティの操作がより簡単で論理的になります。同時に、それは必要性を削除し mapState



mapGetters



mapActions



mapMutations



書くだけでなく、 追加の計算されたプロパティを。



共有



考慮すべき最後のポイントは共有です。Vuex 5では、モジュールに名前を付ける必要がなくなり、それぞれの側が別々で独立していることを覚えています。これにより、必要なときにそれらをインポートし、コンポーネントと同じように必要に応じてデータを使用することができます。複数のストアを一緒に使用する方法について、論理的な疑問が生じます。バージョン4にはまだグローバル名前名があり、このスコープ内のさまざまなストアを使用rootGetters



rootState



て参照する必要があり ます(バージョン3と同様)。Vuex5のアプローチは異なります。



// store/greeter.js
import { defineStore } from 'vuex'

export default defineStore({
  name: 'greeter',
  state () {
    return { greeting: 'Hello' }
  }
})

// store/counter.js
import { defineStore } from 'vuex'
import greeterStore from './greeter'

export default defineStore({
  name: 'counter',

  use () {
    return { greeter: greeterStore }
  },
  
  state () {
    return { count: 0 }
  },
  
  getters: {
    greetingCount () {
      return `${this.greeter.greeting} ${this.count}'
    }
  }
})
      
      





ストアをインポートし、に登録して use



アクセスします。Composition APIを使用すると、すべてがさらに簡単になります。



// store/counter.js
import { ref, computed } from 'vue'
import { defineStore } from 'vuex'
import greeterStore from './greeter'

export default defineStore('counter', ({use}) => {
  const greeter = use(greeterStore)
  const count = 0

  const greetingCount = computed(() => {
    return  `${greeter.greeting} ${this.count}`
  })

  return { count, greetingCount }
})

      
      





言及する価値がある唯一のことは、それuse



がまったく同じよう vuex.store



に機能し、ストアの正しい初期化に責任があるということ です。



TypeScriptのサポート



APIの変更と抽象化の数が少ないため、バージョン4でのTypeScriptのサポートははるかに優れていますが、それでも多くの手動作業が必要です。バージョン5のリリースでは、必要に応じて、必要な場所にタイプを追加できるようになります。



結論



Vuex 5は有望に見え、まさに多くの人が期待しているものです(古いバグの修正、柔軟性の追加)。コアチームのディスカッションとビューの完全なリストは、 VueRFCリポジトリにあります。



All Articles