目次
Vuexとは何ですか?
Vuex は、Vue.js アプリケーション専用に開発された状態管理パターンです。集中ストレージを使用してアプリケーションのすべてのコンポーネントの状態を管理し、対応するルールを使用して状態が予測可能な方法で変化することを保証します。
vuex のフローチャート
Vuex と単純なグローバル オブジェクトの違い
- Vuex の状態ストレージはリアクティブです。 Vue コンポーネントがストアから状態を読み取るときに、ストア内の状態が変化すると、それに応じて対応するコンポーネントが効率的に更新されます。
- ストア内で状態を直接変更することはできません。ストア内の状態を変更する唯一の方法は、ミューテーションを明示的にコミットすることです。これにより、あらゆる状態変化を簡単に追跡できるようになり、アプリケーションをより深く理解するのに役立ついくつかのツールを実装できるようになります。
州
独自のパブリック データ ソースを提供し、すべての共有データはデータと同様にストアの状態に保存されます。
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
name:"张三",
age:12,
count:0
},
})
//调用
this.$store.state.count
//template中直接用
<div>{
{
$store.state.count}}</div>
由于 Vuex 的状态存储是响应式的,从 store 实例中读取状态最简单的方法就是在计算属性中返回某个状态
地図の状態
コンポーネントが複数の状態を取得する必要がある場合、これらの状態を計算されたプロパティとして宣言することは、多少反復的で冗長になります。この問題を解決するには、mapState ヘルパー関数を使用して、計算されたプロパティを生成できます。
import {
mapState } from "vuex";
...
computed: mapState({
// 箭头函数可使代码更简练
name: state => state.name,
// 传字符串参数 'age' 等同于 `state => state.age`
age: 'age',
// 为了能够使用 `this` 获取局部状态,必须使用常规函数
countPlusAge (state) {
return state.age + this.count
}
})
マップされた計算属性の名前が state の子ノードの名前と同じ場合、文字列配列を mapState に渡すこともできます。
computed: mapState([
// 映射 this.age 为 store.state.age
'age',
// 映射 this.name 为 store.state.name
'name'
])
// ===等同于===
computed: mapState({
age:'age', name: 'name'})
ローカルで計算されたプロパティと混合
computed: {
localComputed () {
/* ... */ },
// 使用对象展开运算符将此对象混入到外部对象中
...mapState({
// ...
})
}
ゲッター
Vuex を使用すると、ストア内で「ゲッター」を定義できます (ストアの計算されたプロパティと考えることができます)。計算されたプロパティと同様に、 getter
の戻り値は依存関係に基づいてキャッシュされ、依存関係の値が変更された場合にのみ再計算されます。 Getter の使用を学習すると、state
を通じてデータを繰り返し取得することを避けることができます。
Getter は最初のパラメータとして state を受け入れます。それに応じて state 内のデータを処理し、最終的に必要なデータを返すことができます。
//vuex
getters: {
skillList: state => {
return state.skill.filter(item => item.type === 1)
}
}
//页面
computed: {
skillList() {
return this.$store.getters.skillList
}
}
ゲッターは、他のゲッターを 2 番目の引数として受け入れることもできます。
getters: {
skillList: state => {
return state.skill.filter(item => item.type === 1)
},
skillCount: (state, getters) => {
return getters.skillList.length
},
}
computed: {
skillList() {
return this.$store.getters.skillList
},
count() {
return this.$store.getters.skillCount
}
}
ゲッターは、データを直接返すだけでなく、ゲッターに関数を返させることでパラメーターをゲッターに渡すこともできます。ストア内の配列をクエリするときに非常に便利です。
getters: {
skillList: state => (type) => {
return state.skill.filter(item => item.type === type)
},
skillCount: (state, getters) => (type) => {
return getters.skillList(type).length
},
}
computed: {
skillList() {
return this.$store.getters.skillList(2)
},
count() {
return this.$store.getters.skillCount(2)
}
}
mapGetters ヘルパー関数は、ストア内のゲッターをローカルで計算されたプロパティにマップするだけです。
computed: {
...mapGetters([
'skillList',
'skillCount'
])
}
突然変異
Vuex ストアの状態を変更する唯一の方法は、ミューテーションを送信することです。 Vuex のミューテーションはイベントと非常に似ています。各ミューテーションには文字列イベント タイプ (タイプ) とコールバック関数 (ハンドラー) があります。このコールバック関数は、実際に状態を変更する場所であり、最初のパラメータとして状態を受け取ります。
state: {
count: 1
},
mutations: {
increment (state) {
// 变更状态
state.count++
}
}
突然変異を引き起こす
store.commit('increment')
追加のパラメータを store.commit に渡すことができます。これは、ミューテーションのペイロードです。
mutations: {
incrementByCount (state, n) {
state.count = state.count + n
}
}
store.commit('incrementByCount', 10)
ほとんどの場合、ペイロードはオブジェクトである必要があり、通常受け取るパラメーターにはペイロードという名前が付けられているため、複数のフィールドを含めることができ、記録された変異がより読みやすくなります。
// 定义 mutation
mutations: {
incrementByCount (state, payload) {
state.count = state.count + payload.count
}
}
// 触发 mutation
store.commit('incrementByCount', {
count: 10
})
オブジェクトスタイルの送信
store.commit({
type: 'incrementByCount',
count: 10
})
マップの突然変異
mapMutation は配列形式でパラメータを受け取ります
...mapMutations([
// 将 `this.increment()` 映射为 `this.$store.commit('increment')`
'increment'
]),
mapMutation はオブジェクト形式でパラメータを受け取ります
...mapMutations({
[别名]: [Mutation type]
})
...mapMutations({
add: 'increment'
})
アクション
Action
は Mutation
と似ていますが、次の点が異なります。
- アクションは、状態を直接変更するのではなく、突然変異を送信します。
- アクションには、任意の非同期操作を含めることができます。 vuex の使用中に、複数のミューテーションを 1 つのアクションにマージしたり、アクションを通じて非同期操作を実行したりできます。
基本的な使い方
Action 関数は、ストア インスタンスと同じメソッドとプロパティを持つコンテキスト オブジェクトを受け入れるため、context.commit を呼び出して変更をコミットしたり、context.state と context.getters を通じて状態とゲッターを取得したりできます。
state: {
count: 1
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
// 同步 action
increment (context) {
context.commit('increment')
},
// 异步 action
incrementAsync (context) {
setTimeout(() => {
context.commit('increment')
}, 1000)
}
}
実際には、コードを簡素化するために ES2015 パラメーターの構造化をよく使用します (特に commit を何度も呼び出す必要がある場合)。
actions: {
increment ({
commit }) {
commit('increment')
}
}
急送
アクションは、store.dispatch メソッドを通じてアクションをディスパッチします。
store.dispatch('increment')
ペイロードを送信する
アクションのペイロードである追加パラメータを store.dispatch に渡すことができます。
action: {
increment ({
commit}, payload) {
// 具体 action 内容
}
}
store.dispatch('increment', {
count: 10})
//对象风格的提交方式
store.dispatch({
type: 'increment',
count: 10
})
マップアクション
mapActions ヘルパー関数は、送信されたアクションの記述を簡素化するのに役立ちます。
//mapActions 接收数组格式的参数
...mapActions([
// 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`
'increment'
]),
//mapActions 接收对象格式的参数
//在某些情况,我们需要对 Action 中的函数名重命名以避免和组件内部的变量冲突,这时候我们可以使用对象的方式接收参数:
...mapActions({
[别名]: [Action name]
})
// 例:将 `this.add()` 映射为 `this.$store.dispatch('increment')`
...mapActions({
add: 'increment'
})
コンビネーションアクション
アクションは通常、非同期です。場合によっては、アクションがいつ終了するかを知り、終了後に対応する他の操作を実行する必要があります。さらに重要なのは、複数のアクションを組み合わせて、より複雑な非同期プロセスを処理できることです。
まず、store.dispatch はトリガーされたアクションのハンドラー関数によって返される Promise を処理でき、store.dispatch は依然として Promise を返すことを理解する必要があります。
actions: {
actionA ({
commit }) {
return new Promise((resolve, reject) => {
setTimeout(() => {
commit('someMutation')
resolve()
}, 1000)
})
}
}
これで、次のことが可能になります。
store.dispatch('actionA').then(() => {
// ...
})
別のアクションでも実行できます。
actions: {
// ...
actionB ({
dispatch, commit }) {
return dispatch('actionA').then(() => {
commit('someOtherMutation')
})
}
}
最後に、async /await を利用すると、次のようにアクションを作成できます。
// 假设 getData() 和 getOtherData() 返回的是 Promise
actions: {
async actionA ({
commit }) {
commit('increment', await getData())
},
async actionB ({
dispatch, commit }) {
await dispatch('actionA') // 等待 actionA 完成
commit('increment', await getOtherData())
}
}
モジュール
大規模なプロジェクトに遭遇すると、データ量が多くなり、ストアが非常に肥大化します。
上記の問題を解決するために、Vuex ではストアをモジュールに分割することができます。各モジュールには、独自の状態、突然変異、アクション、ゲッター、さらにはネストされたサブモジュールがあります。
const moduleA = {
state: {
... },
mutations: {
... },
actions: {
... },
getters: {
... }
}
const moduleB = {
state: {
... },
mutations: {
... },
actions: {
... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态