Vuexを使用してVue.jsアプリケーションの状態を管理する方法

提供:Dev Guides
移動先:案内検索

著者は、 Write for DOnations プログラムの一環として、 Open Sourcing MentalIllnessを選択して寄付を受け取りました。

序章

Vuex は、Vue.js用のファーストパーティの開発状態管理ライブラリです。 これはEvanYouによって作成され、現在Vue.jsコアチームによって維持されています。 他の多くの状態管理ライブラリと同様に、Vuexは、 Redux が過去数年にわたって普及してきた原則に従います。データは一方向に流れ、アクションとミューテーションによって、ストアと呼ばれる信頼できる唯一の情報源のデータが変更されます。

Vuex store は、さまざまなメソッドとデータのコレクションです。 操作などのこれらのメソッドの一部は、データがミューテーションに送信される前にデータをフェッチして処理できます。 mutation は、提供された値でストアプロパティを変更または更新するメソッドです。 Getters は、データを変更または結合して新しい状態プロパティを作成できるメソッドです。 これらのゲッターは読み取り専用であり、データを変更しません。 これらは、Vue.jsコンポーネントの計算されたプロパティに似ています。 Vuexの最後のコンポーネントは、 state 、または信頼できる唯一の情報源として機能するデータセットです。

このチュートリアルでは、空港情報を含むカードのリストをレンダリングするアプリケーションを作成します。 クリックすると、これらのカードはVuexワークフローを実行して、選択した空港をお気に入りのリストに追加します。 この例を実行することにより、状態を管理するためのアクションとミューテーションを作成し、計算されたデータを取得するためのゲッターを作成します。

前提条件

ステップ1—サンプルアプリケーションのセットアップ

Vuexで状態がどのように管理されているかを視覚化するために、ビューに表示するデータを使用してプロジェクトを設定します。 このプロジェクトとチュートリアル全体で使用します。

前提条件セクションの説明に従ってfavorite-airportsプロジェクトが作成されたら、このプロジェクトのすべてのローカルデータを保持するディレクトリを作成します。 ターミナルを開き、プロジェクトのルートディレクトリ(favorite-airports)で次のコマンドを実行します。

mkdir src/data
touch src/data/airports.js

これにより、dataディレクトリと、その中に空のairports.jsファイルが作成されます。

選択したテキストエディタで、新しく作成したairports.jsファイルを開き、以下を追加します。

お気に入り-airports/src / data / airports.js

export default [
  {
    name: 'Cincinnati/Northern Kentucky International Airport',
    abbreviation: 'CVG',
    city: 'Hebron',
    state: 'KY'
  },
  {
    name: 'Seattle-Tacoma International Airport',
    abbreviation: 'SEA',
    city: 'Seattle',
    state: 'WA',
  },
  {
    name: 'Minneapolis-Saint Paul International Airport',
    abbreviation: 'MSP',
    city: 'Bloomington',
    state: 'MN',
  },
  {
    name: 'Louis Armstrong New Orleans International Airport',
    abbreviation: 'MSY',
    city: 'New Orleans',
    state: 'LA',
  },
  {
    name: `Chicago O'hare International Airport`,
    abbreviation: 'ORD',
    city: 'Chicago',
    state: 'IL',
  },
  {
    name: `Miami International Airport`,
    abbreviation: 'MIA',
    city: 'Miami',
    state: 'FL',
  }
]

これは、米国内のいくつかの空港で構成されるオブジェクト配列です。 このアプリケーションでは、このデータを反復処理して、name abbreviationcity、およびstateプロパティで構成されるカードを生成します。 ユーザーがカードをクリックすると、dispatchメソッドが実行され、その空港がお気に入りの空港としてVuex州に追加されます。

data/airports.jsを保存して、ターミナルに戻ります。

その手順が完了したら、AirportCard.vueという名前の単一ファイルコンポーネント(SFC)を作成します。 このファイルは、プロジェクトのcomponentsディレクトリにあります。 このコンポーネントには、エアポートカードのすべてのスタイルとロジックが含まれます。 ターミナルで、touchコマンドを使用して.vueファイルを作成します。

touch src/components/AirportCard.vue

テキストエディタでAirportCard.vueを開き、以下を追加します。

お気に入り-airports/src / components / AirportCard.vue

<template>
  <div class="airport">
    <p>{{ airport.abbreviation }}</p>
    <p>{{ airport.name }}</p>
    <p>{{ airport.city }}, {{ airport.state }}</p>
  </div>
</template>

<script>
export default {
  props: {
    airport: {
      type: Object,
      required: true
    }
  }
}
</script>

<style scoped>
.airport {
  border: 3px solid;
  border-radius: .5rem;
  padding: 1rem;
  margin-bottom: 1rem;
}

.airport p:first-child {
  font-weight: bold;
  font-size: 2.5rem;
  margin: 1rem 0;
}

.airport p:last-child {
  font-style: italic;
  font-size: .8rem;
}
</style>

このコードスニペットにCSSが含まれていることに気付くかもしれません。 AirportCard.vueコンポーネントでは、ラッパー<div>airportのクラスが含まれています。 このCSSは、各空港に「カード」の外観を与えるために境界線を追加することにより、生成されたHTMLにスタイルを追加します。 :first-child:last-childは、div内のHTMLの最初と最後のpタグに異なるスタイルを適用する疑似セレクターです。 airportのクラスで。 それに加えて、このコンポーネントには prop が含まれていることに気付くかもしれません。これは、Vue.jsでは親コンポーネントから子コンポーネントにデータを渡す方法です。

ファイルを保存して終了します。

セットアップを完了する前に、既存のApp.vueコンポーネントを次のコードに置き換えます。

お気に入り-airports/src / App.vue

<template>
  <div class="wrapper">
    <div v-for="airport in airports" :key="airport.abbreviation">
      <airport-card :airport="airport" />
    </div>
  </div>
</template>

<script>
import { ref } from 'vue'
import allAirports from '@/data/airports.js'
import AirportCard from '@/components/AirportCard.vue'

export default {
  components: {
    AirportCard
  },
  setup() {
    const airports = ref(allAirports)
    return { airports }
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}

.wrapper {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-column-gap: 1rem;
  max-width: 960px;
  margin: 0 auto;
}

p,
h3 {
  grid-column: span 3;
}
</style>

このコードには、v-forループが含まれています。このループは、airports.jsデータを反復処理し、プロップ:airportを介して渡された空港データを使用して一連のAirportCards.vueコンポーネントをレンダリングします。 ]。 このコードを保存して、コマンドラインに戻ります。

プロジェクトをセットアップしたら、ターミナルでnpm run serveコマンドを使用してローカル開発サーバーを実行します。

npm run serve

これにより、localhostで、通常はポート8080でサーバーが起動します。 選択したWebブラウザーを開き、localhost:8080にアクセスして以下を確認します。

サンプルアプリケーションがセットアップされたので、次のステップでVuexライブラリをインストールし、storeを作成します。 このストアは、状態、ミューテーション、アクション、ゲッターなど、さまざまなVuexアイテムのコレクションです。 これを説明するために、ディスパッチメソッドを実行します。これにより、アプリのお気に入りセクションに空港が追加されます。

ステップ2—Vuexをインストールする

Webベースのアプリケーションで作業する場合、多くの場合、stateで作業します。 状態は、特定の時点でのデータのコレクションです。 この状態は、dispatchおよびcommitメソッドを介したユーザー操作によって変更できます。 ユーザーがデータを変更すると、ディスパッチイベントが実行され、データが mutation に渡され、stateオブジェクトが更新されます。

状態の更新にアプローチする方法はいくつかあります。 一部の開発者は、actionsをスキップして、mutatationsに直接進みます。 ただし、このチュートリアルでは、常にactionを実行し、mutationを呼び出します。 このようにして、アクション内に複数のミューテーションを含めることができます。 Vuexの基本的なルールは、ミューテーションには1つのジョブと1つのジョブのみがあるということです。ストアを更新します。 アクションは、データの結合、データのフェッチ、JavaScriptロジックの実行など、さまざまなことを実行できます。

アクションに加えて、gettersもあります。 ゲッターは、複数の状態値を1つの値に結合する方法です。 Vue.jsの計算されたプロパティに精通している場合、ゲッターは状態固有の計算されたプロパティと考えることができます。

Vuexの用語をカバーしたら、Vuexのインストールと統合を開始します。 ターミナルを開き、次のコマンドを実行します。

npm install vuex@next --save

このコマンドは、Vue.js 3.xと最も互換性のあるバージョンのVuexをインストールし、package.jsonファイルに保存します。 次に、ストアのディレクトリとインデックスファイルを作成します。 mkdirコマンドを使用してディレクトリを作成し、touchを使用して新しいファイルを作成します。

mkdir src/store
touch src/store/index.js

テキストエディタを開き、store/index.jsファイルでVuexストアを初期化します。 これを行うには、VuexのcreateStore関数を利用する必要があります。

空港-favorites/src / store / index.js

import { createStore } from 'vuex'

export default createStore({
  
})

また、後でmain.jsファイルにインポートするため、これをexportします。

この時点で、Vuexストアがセットアップされていますが、アプリケーションはまだVuexストアまたはその使用方法を認識していません。 ストアを完全に初期化するには、importmain.jsファイルに入れます。 テキストエディタで、src/main.jsファイルを開きます。

createApp(App)の直後に、useメソッドをチェーンし、次の強調表示されたコードに示すように、インポートするストアに渡します。

お気に入り-airports/src / main.js

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

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

useメソッドを連鎖させたら、このファイルを保存します。 useメソッドは、アプリケーションのビルド時にどのコードをバンドルするかをVueアプリケーションに指示します。 この場合、Vuexストアを「使用」またはバンドルするようにVueに指示しています。

次のセクションに進む前に、状態値をストアに追加し、App.vueファイルで参照してください。 store/index.jsファイルを開き、次のオブジェクトと値を追加します。

お気に入り-airports/src / store / index.js

import { createStore } from 'vuex'

export default createStore({
state: {
    firstName: 'John',
    lastName: 'Doe'
  },
mutations: {

},
actions: {

},
getters: {

}
})

これらのプロパティは、ストアが保持するデータのタイプを反映します。状態(グローバルデータ)のstatemutations(データを変更することをコミット)、actions(変更を呼び出すディスパッチ)、およびgettersstore計算されたプロパティ)。

store/index.jsを保存し、テキストエディタでApp.vueファイルを開いて、次を追加します。

お気に入り-airports/src / App.vue

<template>
  <div class="wrapper">
    <p>{{ $store.state.firstName }} {{ $store.state.lastName }}</p>
    <div v-for="airport in airports" :key="airport.abbreviation">
      <airport-card :airport="airport" />
    </div>
  </div>
</template>
...

この場合の$storeは、main.jsファイルで初期化したグローバルストアです。 this.$storeをコンソールにログインすると、ストアobjectが表示されます。 そこから、コードはドット表記を介して表示するプロパティにアクセスします。

App.vueを保存して、Webブラウザを開きます。 空港カードの上に、Vuexストアに保存した名前と名前が表示されます。 これらは、それぞれfirstNamelastNameのデフォルト値です。

このステップでは、Vuexをインストールし、Vuexストアを作成しました。 いくつかのデフォルトのストアデータを追加し、ドットの概念を使用して$storeオブジェクトとともにビューに表示しました。 次のステップでは、actionsおよびmutationsを介してVuexストアを更新し、gettersと組み合わせたデータを取得します。

ステップ3—アクション、ミューテーション、およびゲッターを作成する

ステップ2では、Vuexを手動でインストールし、プロジェクトに統合しました。 このステップでは、ブラウザに名前と名前がまだレンダリングされていますが、データを1つの文字列としてレンダリングするVuexゲッターを作成します。 前述のように、VuexゲッターはVuexストアの計算されたプロパティと考えることができます。

ゲッターを作成するには、選択したテキストエディターでsrc/store/index.jsファイルを開きます。 開いたら、関数を値としてgettersオブジェクトにプロパティを作成します。 プロパティの名前は、後でゲッターにアクセスする方法です。

次の強調表示されたコードを追加します。

お気に入り-airports/src / store / index.js

import { createStore } from 'vuex'

export default createStore({
  state: {
    firstName: 'John',
    lastName: 'Doe'
  },
  ...
  getters: {
    fullName: function () {
      
    }
  }
})

この場合、関数を使用して名前と名前を組み合わせ、結果のプロパティをfullNameとして保存します。 関数内で、Vuexストア内にあるstateオブジェクトを渡す必要があります。 そこから、名前と名前が補間された文字列を返します。

お気に入り-airports/src / store / index.js

import { createStore } from 'vuex'

export default createStore({
  state: {
    firstName: 'John',
    lastName: 'Doe'
  },
  ...
  getters: {
    fullName: function (state) {
      return `${state.firstName} ${state.lastName}`
    }
  }
})

ここでは、テンプレートリテラルを使用して、firstNamelastNameを1つの文字列にまとめています。

このファイルを保存して、App.vueに戻ります。 このファイルで、最初と最後の値を削除し、それらをゲッターに置き換えます。

お気に入り-airports/src / App.vue

<template>
  <div class="wrapper">
    <p>{{ $store.getters.fullName }}</p>
    <div v-for="airport in airports" :key="airport.abbreviation">
      <airport-card :airport="airport" />
    </div>
  </div>
</template>
...

この変更を行ってファイルを保存すると、ブラウザはホットリロードします。 以前と同じようにブラウザに名前と名前が表示されますが、現在はゲッターを利用しています。 Vuexストアの名前の1つを変更すると、ゲッターは自動的に更新されます。

ゲッターから進んで、actionsがあります。 最後のステップで述べたように、このチュートリアルでは、データを直接変更するのではなく、常にアクションを使用します。

このプロジェクトでは、ユーザーがカードをクリックしたときに、空港のデータを「お気に入り」リストに追加します。 最初にアクションとミューテーションを作成し、後でv-onディレクティブを使用してクリックイベントに割り当てます。

アクションを作成するには、テキストエディタでsrc/store/index.jsファイルを開きます。 ストアのactionsセクションで、関数を作成します。 getterと同様に、関数名は後でアクションを参照する方法になります。 この関数にaddToFavoritesという名前を付けます。

お気に入り-airports/src / store / index.js

import { createStore } from 'vuex'

export default createStore({
  state: {
    firstName: 'John',
    lastName: 'Doe',
    favorites: [] // will store favorites here
  },
  mutations: {
  
  },
  actions: {
    addToFavorites() {
      
    }
  },
  getters: {
    fullName: function (state) {
      return `${state.firstName} ${state.lastName}`
    }
}
})

アクションは、context(Vueアプリ自体)とpayload(ストアに追加するデータ)の2つの引数を受け入れます。 コンテキストにはcommitメソッドが関連付けられており、後で作成するミューテーションを呼び出すために使用します。

お気に入り-airports/src / store / index.js

import { createStore } from 'vuex'

export default createStore({
  state: {
    firstName: 'John',
    lastName: 'Doe',
    favorites: []
  },
  mutations: {
  
  },
  actions: {
    addToFavorites(context, payload) {
      context.commit('UPDATE_FAVORITES', payload)
    }
  },
  getters: {
    fullName: function (state) {
      return `${state.firstName} ${state.lastName}`
    }
 }
})

commitメソッドは、呼び出すミューテーションの名前とpayloadまたはミューテーションが状態を置き換えるデータの2つの引数も受け入れます。

このコードでは、ミューテーションにUPDATE_FAVORITESという名前を付けています。 ミューテーション名は不可知論的であり、特定のアクションにちなんで名付けられてはなりません。 たとえば、ADD_FAVORITEREMOVE_FAVORITEのような変更は、データの一部を削除または追加するなどのロジックを意味します。 ミューテーションには1つのジョブと1つのジョブのみが必要であるため、これは理想的ではありません。状態を更新します。 データの追加と削除を区別するために、2つの異なるactionsを使用して、お気に入りの空港をアレイから削除または追加し、UPDATE_FAVORITESという単一のミューテーションを実行して、アレイを更新します。渡されました。 ストア内のミューテーションの量を最小限に抑えると、Vuexストアの複雑さとサイズが大きくなるため、管理が容易になります。

次に、このアクションにロジックを追加します。 空港を「お気に入り」として追加する場合、そのペイロード(空港データ)を既存のアレイに追加します。 これを行うには、JavaScriptでpushメソッドを使用できます。

お気に入り-airports/src / store / index.js

import { createStore } from 'vuex'

export default createStore({
  state: {
    firstName: 'John',
    lastName: 'Doe',
    favorites: []
  },
  mutations: {
  
  },
  actions: {
    addToFavorites(context, payload) {
      const favorites = context.state.favorites
      favorites.push(payload)
      context.commit('UPDATE_FAVORITES', favorites)
    }
  },
  getters: {
    fullName: function (state) {
      return `${state.firstName} ${state.lastName}`
    }
 }
})

この時点で、payloadfavorites配列に追加し、変更された配列を新しいデータとして変更を呼び出すようにアクションが設定されています。 次に、UPDATE_FAVORITESミューテーションを定義します。 次のコードを追加して、favoritesアレイを新しいアレイとして設定します。

お気に入り-airports/src / store / index.js

import { createStore } from 'vuex'

export default createStore({
  state: {
      firstName: 'John',
    lastName: 'Doe',
    favorites: []
    },
  mutations: {
    UPDATE_FAVORITES(state, payload) {
      state.favorites = payload
    }
  },
  actions: {
    addToFavorites(context, payload) {
      const favorites = context.state.favorites
      favorites.push(payload)
      context.commit('UPDATE_FAVORITES', favorites)
    }
  },
  getters: {
    fullName: function (state) {
      return `${state.firstName} ${state.lastName}`
    }
 }
})

アクションとミューテーションができたので、このファイルを保存できます。

このアクションを実行するには、ユーザーがカードをクリックしたときにdispatchイベントを呼び出すことができます。 これは、v-onディレクティブを使用して行います。

テキストエディタでApp.vueファイルを開きます。 <airport-card />コンポーネントで、v-onディレクティブの短縮構文(@)を追加し、イベントをclickにします。

お気に入り-airports/src / App.vue

<template>
  <div class="wrapper">
    <p>{{ $store.getters.fullName }}</p>
    <div v-for="airport in airports" :key="airport.abbreviation">
      <airport-card :airport="airport" @click="$store.dispatch('addToFavorites', airport)" />
    </div>
    <h2 v-if="$store.state.favorites.length">Favorites</h2>
    <div v-for="airport in $store.state.favorites" :key="airport.abbreviation">
      <airport-card :airport="airport"  />
    </div>
  </div>
</template>
...

dispatch関数は、アクション名とアクションに送信するペイロードデータの2つの引数を受け入れます。

このファイルを保存して、ブラウザで開きます。 これで、空港カードをクリックすると、アクションによってミューテーションが呼び出され、状態が更新され、空港がお気に入りのプロパティに追加されます。

このステップでは、前に作成したVuexストアを拡張しました。 配列をコピーし、その配列に新しいアイテムをプッシュするアクションを作成しました。 そのアクションはミューテーションと呼ばれ、状態を更新しました。 それに加えて、gettersと、それらを活用してVuexストアの読み取り専用値を組み合わせたり変更したりして新しいプロパティを作成する方法について学びました。

最後のステップでは、Vuexモジュールを実装します。 モジュールは、Vuexストアをより小さなVuexストアに分割するための優れた方法です。 これは、Vuexストアの栽培者のサイズと複雑さが大きくなる場合に役立ちます。

ステップ4—Vuexモジュールの作成

モジュールは、単一のVuexストアに結合された小さなVuexストアです。 これは、複数のVue.jsコンポーネントがApp.vueなどの単一の.vueファイルにインポートされる方法と似ています。 このステップでは、このVuexストアを2つの別々のモジュールに分割します。 1つのモジュールはuser状態用で、もう1つはairport状態、アクション、およびミューテーションに固有です。

ターミナルで、cdstoreディレクトリに移動し、touchコマンドを使用して2つの別々のファイルを作成します。

touch src/store/user.module.js
touch src/store/airports.module.js

user.module.jsファイル内に、次のコードを追加して、デフォルトでエクスポートされるオブジェクトを作成します。

お気に入り-airports/src / store / user.module.js

export default {
  namespaced: true
}

また、プロパティnamespacedを追加し、その値をtrueとします。 namespaceプロパティを使用すると、後でドット表記のプロパティにアクセスするときにモジュール名を参照できるようになります。

このオブジェクト内に、ユーザーに関連付けられているstateおよびgetter情報を追加します。

お気に入り-airports/src / store / user.module.js

export default {
  namespaced: true,
  state: {
    firstName: 'John',
    lastName: 'Doe'
  },
  getters: {
    fullName: function (state) {
      return `${state.firstName} ${state.lastName}`
    }
  }
}

ユーザーモジュールには、ユーザー情報に必要なすべてのものが含まれています。 ファイルを保存して終了します。

先に進み、airports.module.jsファイルで同じことを行います。 テキストエディタでairports.module.jsファイルを開き、次を追加します。

お気に入り-airports/src / store / airports.module.js

export default {
  state: {
    favorites: []
  },
  mutations: {
    UPDATE_FAVORITES(state, payload) {
      state.favorites = payload
    }
  },
  actions: {
    addToFavorites(context, payload) {
      const favorites = context.state.favorites
      favorites.push(payload)
      context.commit('UPDATE_FAVORITES', favorites)
    }
  },
}

airport関連のミューテーション、アクション、および状態を設定したので、airports.module.jsを保存できます。

次に、これら2つのファイルをメインのstore/index.jsファイルにimportします。 テキストエディタで、store/index.jsファイルを開き、statemutationsactions、およびgettersプロパティを削除します。 ファイルは次のスニペットのようになります。

お気に入り-airports/src / store / index.js

import { createStore } from 'vuex'

export default createStore({

})

モジュールを登録するには、次の強調表示されたコードを使用して、モジュールをこのindex.jsファイルにインポートする必要があります。

お気に入り-airports/src / store / index.js

import { createStore } from 'vuex'
import UserModule from './user.module.js'
import AirportsModule from './airports.module.js'

export default createStore({

})

ここから、値としてオブジェクトを持つmodulesというプロパティが必要になります。 このオブジェクト内のプロパティ名は、Vuexモジュールの名前になります。 モジュール名の値は、インポートされたモジュール自体です。

お気に入り-airports/src / store / index.js

import { createStore } from 'vuex'
import UserModule from './user.module.js'
import AirportsModule from './airports.module.js'

export default createStore({
modules: {
  user: UserModule,
  airports: AirportsModule
}
})

このファイルを保存すると、モジュールが登録され、単一のVuexストアに結合されます。 store/index.jsを保存し、App.vueファイルを開いて更新し、新しく作成されたモジュールを参照します。

お気に入り-airports/src / App.vue

<template>
  <div class="wrapper">
    <p>{{ $store.getters['user/fullName'] }}</p>
    <div v-for="airport in airports" :key="airport.abbreviation">
      <airport-card :airport="airport" @click="$store.dispatch('addToFavorites', airport)" />
    </div>
    <h2 v-if="$store.state.airports.favorites.length">Favorites</h2>
    <div v-for="airport in $store.state.airports.favorites" :key="airport.abbreviation">
      <airport-card :airport="airport"  />
    </div>
  </div>
</template>
...

これで、Vuexセットアップのモジュラーバージョンができました。

このステップでは、既存のVuexストアをモジュールと呼ばれる小さなチャンクにセグメント化しました。 これらのモジュールは、関連するストアのプロパティを小さなVuexストアにグループ化するための優れた方法です。 また、App.vueを更新して、各モジュールの状態とディスパッチイベントを参照しました。

結論

大まかに言えば、状態管理はデータの更新がすべてです。 この設定では、状態のデータはアプリケーション全体でグローバルであり、信頼できる唯一の情報源として機能します。これは、アクションとミューテーションの形式の明示的な関数でのみ更新できます。 このチュートリアルでは、statemutationsactions、およびgettersの例を実行し、これらの各プロパティがどのように独自の目的を持っているかを確認しました。更新サイクル。

Vuex、アクション、ミューテーション、およびモジュールの詳細については、Vue.jsコアチームによって作成された公式Vuexドキュメントを確認してください。 Vueのその他のチュートリアルについては、Vue.jsシリーズページを使用してWebサイトを開発する方法を確認してください。