Vuex は、Vue.js アプリケーション用に特別に開発された状態管理モデルで、アプリケーションのすべてのコンポーネントの状態を一元的に保存および管理します。この記事では、vuex の使用方法に関するドキュメントを皆さんに紹介します。必要な友達は参照してください
Vuex とは何ですか?
Vuex は、Vue.js アプリケーション専用に開発された状態管理パターンです。集中ストレージを使用してアプリケーションのすべてのコンポーネントのステータスを管理し、対応するルールを使用してステータスが予測可能な方法で変化することを保証します。 Vuex は、Vue の公式デバッグ ツール devtools 拡張機能にも統合されており、ゼロ構成のタイムトラベル デバッグ、ステータス スナップショットのインポートおよびエクスポートなどの高度なデバッグ機能を提供します。
インストール
直接ダウンロード CDN リファレンス
<script src="/path/to/vue.js"></script> <script src="/path/to/vuex.js"></script>
npm
npm install vuex --save
モジュラーパッケージングシステムでは、Vue.use() を介して Vuex を明示的にインストールする必要があります。
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex)
Vuex は、Vue.js アプリケーション専用に開発された状態管理モデルで、アプリケーションのすべてのコンポーネントの状態を一元的に保存および管理します。
状態管理には次の部分的な状態が含まれます:
状態はアプリケーションのデータソースを駆動します。
ビューは実際のような方法で状態をビューにマップします。
アクションは、ビューへのユーザー入力によって引き起こされる状態の変化に応答します。
中規模および大規模の単一ページ アプリケーションの共有ステータスの管理にご協力ください。
state
単一の状態ツリー、Vuex は単一の状態ツリーを使用して、アプリケーションレベルのすべての状態を 1 つのオブジェクトに含めます。
VueコンポーネントでVuexの状態を取得します。
Vuex の状態ストレージはリアクティブであるため、ストア インスタンスから状態を読み取る最も簡単な方法
計算されたプロパティで特定の状態を返すことです。
Counterコンポーネントを作成します
const Counter = { template: '<p>{{ count }}</p>' computed: { count (){ return store.state.count } } }
store.state.countが変更されるたびに、計算されたプロパティが再計算され、関連するDOMの更新がトリガーされます
Vuexは、ルートコンポーネントから状態を転送するメカニズムを提供しますストア オプションを介して各サブコンポーネントに「注入」します (Vue.use(Vuex) を呼び出す必要があります):
const app = new Vue({ el:'#app', // 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所 有的子组件 store, components: {Counter}, template: ' <p class="app"> <counter></counter> </p> ' })
ストア オプションをルート インスタンスに登録すると、ストア インスタンスがすべてのサブコンポーネントに登録されます。コンポーネントの下のコンポーネント、およびサブコンポーネントには this.$store を通じてアクセスできます。 counter の実装を更新します:
const Counter = { template : '<p>{{ count }}</p>', computed: { count this.$store.state.count } }
mapState helper function
コンポーネントが複数の状態を取得する必要がある場合、これらの状態を計算されたプロパティとして宣言するのは冗長です。
この問題を解決するには、mapState ヘルパー関数を使用して、計算されたプロパティを生成できます。
// 在单独构建的版本中辅助函数为 Vuex.mapState import { mapState } from 'vuex' export default { computed: mapState({ // 箭头函数可以使代码更简洁 count: state => state.count, // 传字符串参数 ‘count' 等同于 ‘state => state.count' countAlias: 'count', // 为了能够使用 ‘this' 获取局部状态,必须使用常规函数 countPlusLocalState(state) { return state.count + this.localCount } }) }
マッピングされた計算属性の名前がstateの子ノードの名前と同じ場合、mapStateに文字列配列を渡すこともできます。
computed: mapState([ // 映射 this.count 为 store.state.count 'count' ])
コンポーネントはローカル状態を保持します。
Getters
リストのフィルタリングや計算など、ストア内の状態から何らかの状態を導出する必要がある場合があります。
computed: { doneTodosCount() { return this.$store.state.todos.filter(todo => todo.done).length } }
Vuexではストア内でゲッターを定義できます(ストアの計算されたプロパティと考えることができます)
ゲッターは状態を最初のパラメータとして受け取ります。
const store = new Vuex.Store({ state: { todos:[ {id:1, text: '...' ,done: true}, {id:2,text:'...',done: false} ] }, getters: { doneTodos: state => { return state.todos.filter(todo=> todo.done) } } })
ゲッターは、store.getters オブジェクトとして公開されます:
store.getters.doneTodos // [{id:1,text: '...',done:true}]
ゲッターは、他のゲッターを 2 番目のパラメーターとして受け入れることもできます:
getters: { doneTodosCount: (state,getters) => { return getters.doneTodos.length } } store.getters.doneTodosCount // -> 1
簡単に使用できます
computed: { doneTodosCount() { return this.$store.getters.doneTodosCount } }
mapGetters ヘルパー関数
mapGetters ヘルパー関数は、ストア内の単なるゲッターです。ローカルで計算されたプロパティにマップします。
import {mapGetter} form 'vuex' export default { computed: { // 使用对象展开运算符将 getters 混入 ...mapGetters([ ‘doneTodosCount', 'anotherGetter' ]) } }
オブジェクトプロパティを使用するときに、ゲッタープロパティに別の名前を付けたい場合
mapGetters({ // 映射 this.doneCount 为 store.getters.doneTodosCount doneCount: 'doneTodosCount' })
Vuexストアで状態を変更する唯一の方法は、Vuexでミューテーションを送信することです
それぞれイベントと非常によく似ています。各ミューテーションには文字列イベント タイプとコールバック関数があります。このコールバック関数は、実際に状態変更を行う場所です。そして、状態を最初のパラメータとして受け入れます。
const store = new Vue.Store({ state: { count: 1 }, mutations: { inctement (state) { state.count++ } } })
この関数は、increment 型の突然変異がトリガーされたときに呼び出されます。 「変異ハンドラーを起動するには、対応するタイプで store.commit メソッドを呼び出す必要があります。ペイロード (ペイロード) を送信します。store.commit に追加のパラメーター、つまり変異ペイロードを渡すことができます: "
store.commit('increment')
ほとんどの場合、ペイロードはオブジェクトである必要があり、複数のフィールドを含めることができ、変更をより簡単に記録できます。
mutations: { increment (state,payload) { state.count += payload.amount } } store.commit('increment', { amount:10 })
对象风格的提交方式
提交mutation 的另一种方式直接使用包含 type 属性的对象:
store.commit({ type: 'increment', amount:10 })
当使用对象风格的提交方式,整个对象作为载荷传给mutation 函数,因此handler保持不变:
mutations: { increment (state, payload) { state.count += payload.amount } }
Mutations 需遵守vue 的响应规则
既然Vuex的store 中的状态是响应式的,那么当我们变更状态时,监视状态的vue更新 ,这也意味值Vue 中的mutation 也需要与使用 Vue 一样遵守一些注意事项。
1. 最好提前在你的store 中初始化好所有的所需要的属性。
2.当需要在对象上提交新属性时,你应该使用
Vue.set(obj, 'newProp', 123)
使用新对象代替老对象 state.obj= {...state.obj ,newProp: 123}
使用常量替代 Mutation 事件类型
使用常量替代 mutation 事件类型在各种 Flux 实现中是很常见的模式
export const SOME_MUTATION = 'SOME_MUTATION'; import Vuex from 'vuex' import {SOME_MUTATION } from './mutation-types' const store = new Vuex.Store({ state: {...} mutations: { // 我们可以使用 ES2015 风格的计算属性命名功能来使用一个常量作为函数名 [SOME_MUTATION] (state) { // mutate state } } })
mutation 必须是同步函数
一条重要的原则是记住 mutation 必须是同步函数。
mutations: { someMutation (state) { api.callAsyncMethod(() => { state.count++ }) } }
在组件中提交 Mutations
你可以在组件中使用 this.$store.commit('xxx') 提交 mutation,或者使使用 mapMutations辅助函数将组建中的methods 映射为 store.commit 调用 (需要在根节点注入 store)
import {mapMutations} from 'vuex' expor default { methods: { mapMutations([ methods: { mapMutations([ 'increment' // 映射 this.increment() 为 this.$store.commit('increment') ]), mapMutations({ add: 'increment' // 映射 this.add() 为 this.$store.commit('increment') }) } ]) } }
Actions
在mutation 中混异步调用会导致你的程序很难调试。
Actions
Action 类似于 mutation,不同在于。
Action 提交的是 mutation ,而不是直接变更状态。
Action 可以包含任意异步操作。
注册一个简单的 action
const store = new Vuex.Store({ state: { count:0 }, mutations: { increment (state) { state.count++ } }, actions: { increment (context){ context.commit('increment') } } })
Action 函数接受一个与store 实例具有相同方法和属性的context 对象,因此你可以调用 context.commit 提交一个mutation,或者通过 context.state 和context.getters 来获取 state 和 getters 当我们在之后介绍到Modules时,你就知道 context 对象为什么不是store 实例本身了。
actions: { increment({commit}){ commit('increment') } }
分发 Action
Action 通过 store.dispatch 方法触发:
store.dispatch('increment')
我们可以在 action 内部执行异步操作。
actions: { incrementAsync({commit}){ setTimeout(() => { commit('increment') },1000) } }
Actions 支持同样的载荷方式和对象方式进行分发
// 以载荷形式分发 store.dispatch('incrementAsync',{ amount:10 }) // 以对象形式分发 store.dispatch({ type: 'incrementAsync', amount:10 })
在组件中分发 Action
你在组件中使用 this.$store.dispatch('xxx')
分发 action,或者使用map Actions辅助函数将组件的methods 映射为store.dispatch 调用
import {mapActions } from 'vuex' export default{ methods:([ 'increment' // 映射 this.increment() 为 this.$store.dispatch('increment') ]) mapActions({ add: 'inctement' // 映射 this.add() 为 this.$store.dispatch('increment') }) }
组合 Actions
Action 通常是异步的,那么如何知道 action 什么时候结束。
你需要明白 store.dispatch 可以处理被处触发的action 的回调函数返回的Promise并且 store.dispatch 仍旧返回Promise
actions: { actionA({commit}){ return new Promise((resolve)=>{ setTimeout (() => { commit('someMutation') resolve() },1000) }) } }
现在你可以
store.dispatch('actionA').then(()=>{ //... })
在另一个 action 中也可以
actions: { actionB({dispath,commit}){ return dispatch('actionA').then(() => { commit('someOtherMutation') }) } }
我们利用async/ await
// 假设 getData() 和 getOther() 返回的是一个 Promis actions:{ async actionA ({commit}){ commit('gotData',await getData()) }, async actionB({dispatch,commit}){ await dispatch('actionA') // 等待 actionA 完成 commit('goOtherData', await getOtherData()) } }
Modules
使用单一状态树,当应用变的很大的时候,store 对象会变的臃肿不堪。
Vuex 允许我们将store 分割到模块。每一个模块都有自己的state, mutation,action, getters, 甚至是嵌套子模块从上到下进行类似的分割。
const moduleA = { state: {...}, mutations: {...} actions: {...} getters:{...} } const moduleA = { state: {...}, mutations: {...} actions: {...} } const store = new Vuex.Store({ modules: { a:moduleA, b:moduleB } }) store.state.a // -> moduleA 的状态 store.state.b // -> moduleB 的状态
模块的局部状态
对于模块内部的 mutation 和 getter, 接收的第一个参数是模块的局部状态。
const moduleA = { state: {count:0}, mutations: { increment (state) { // state 模块的局部状态 state.count++ } }, getters: { doubleCount (state) { return state.count * 2 } } }
同样对于模块内部的action, context.state 是局部状态,根节点的窗台石context.rootState:
const moduleA = { actions: { incrementIfOddOnRootSum ({state, commit ,rootState}) { if((state.count + rootState.count) %2 ===1){ commit('increment') } } } }
对于模块内部的getter,跟节点状态会作为第三个参数:
const moduleA = { getters: { getters: { sumWithRootCount (state,getters,rootState) { return state.count + rootState.count } } } }
命名空间
模块内部的action, mutation , 和 getter 现在仍然注册在全局命名空间 这样保证了多个模块能够响应同一 mutation 或 action. 也可以通过添加前缀 或者 后缀的
方式隔离各个模块,以免冲突。
// 定义 getter, action , 和 mutation 的名称为常量,以模块名 ‘todo' 为前缀。 export const DONE_COUNT = 'todos/DONE_COUNT' export const FETCH_ALL = 'todos/FETCH_ALL' export const TOGGLE_DONE = 'todos/TOGGLE_DONE' import * as types form '../types' // 使用添加了解前缀的名称定义, getter, action 和 mutation const todosModule = { state : {todo: []}, getters: { [type.DONE_COUNT] (state) { } } actions: { [types.FETCH_ALL] (context,payload) { } }, mutations: { [type.TOGGLE_DONE] (state, payload) } }
模块动态注册
在store 创建之后,你可以使用 store.registerModule 方法注册模块。
store.registerModule('myModule',{})
模块的状态将是 store.state.myModule.
模块动态注册功能可以使让其他Vue 插件为了应用的store 附加新模块
以此来分割Vuex 的状态管理。
项目结构
Vuex 并不限制你的代码结构。但是它规定了一些需要遵守的规则:
1.应用层级的状态应该集中到单个store 对象中。
2.提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
3.异步逻辑应该封装到action 里面。
只要你遵守以上规则,如何组织代码随你便。如果你的 store 文件太大,只需将 action、mutation、和 getters 分割到单独的文件对于大型应用,我们会希望把 Vuex 相关代码分割到模块中。下面是项目结构示例
├── index.html ├── main.js ├── api │ └── ... # 抽取出API请求 ├── components │ ├── App.vue │ └── ... └── store ├── index.js # 我们组装模块并导出 store 的地方 ├── actions.js # 根级别的 action ├── mutations.js # 根级别的 mutation └── modules ├── cart.js # 购物车模块 └── products.js # 产品模块
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
以上がvuex の中国語ドキュメントの詳細な紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。