用於多組件共享狀態,若是不打算開發大型單頁應用,使用 Vuex 多是繁瑣冗餘的。確實是如此——若是應用夠簡單,您最好不要使用 Vuex。可以使用簡單Bus總線的方式來管理共享的數據詳見(http://www.cnblogs.com/fanlinqiang/p/7756566.html)。可是,若是您須要構建是一箇中大型單頁應用,vuex能夠更好地在組件外部管理狀態html
引入:vue
src/store/index.jses6
import Vue from 'vue' import Vuex from 'vuex' import createLogger from 'vuex/dist/logger' Vue.use(Vuex) const store = new Vuex.Store({ plugins: [createLogger()], state: { count: 0, todos: [ { id: 1, text: '...', done: true }, { id: 2, text: '...', done: false } ] }, getters: { doneTodos: state => { return state.todos.filter(todo => todo.done) }, doneTodosCount: (state, getters) => { //注:Getter 也能夠接受其餘 getter 做爲第二個參數 return getters.doneTodos.length }, getTodoById: (state) => (id) => { //getter 返回一個函數來實現給 getter 傳參 return state.todos.find(todo => todo.id === id) } }, mutations: { //mutation 必須同步執行,爲解決這個問題咱們引入了action increment (state, payload) { //store.commit 傳入額外的參數,即 mutation 的 載荷(payload) state.count += payload.amount } }, actions: { //Action 函數接受一個與 store 實例具備相同方法和屬性的 context 對象, //所以你能夠調用 context.commit 提交一個 mutation,或者經過 context.state 和 context.getters 來獲取 state 和 getters。 increment (context) { context.commit('increment') }, increment ({ commit }) { //es6解構 commit('increment') }, incrementAsync ({ commit }) { setTimeout(() => { commit('increment') }, 1000) }, //store.dispatch 能夠處理被觸發的 action 的處理函數返回的 Promise,而且 store.dispatch 仍舊返回 Promise actionA ({ commit }) { return new Promise((resolve, reject) => { setTimeout(() => { commit('someMutation') resolve() }, 1000) }) }, actionB ({ dispatch, commit }) { return dispatch('actionA').then(() => { commit('someOtherMutation') }) } // 假設 getData() 和 getOtherData() 返回的是 Promise async actionA ({ commit }) { commit('gotData', await getData()) }, async actionB ({ dispatch, commit }) { await dispatch('actionA') // 等待 actionA 完成 commit('gotOtherData', await getOtherData()) } } }) export default store
最好提早在你的 store 中初始化好全部所需屬性。當須要在對象上添加新屬性時,你應該使用 Vue.set(obj, 'newProp', 123), 或者
以新對象替換老對象。例如,利用 stage-3 的對象展開運算符咱們能夠這樣寫:web
state.obj = { ...state.obj, newProp: 123 }
組件a:vuex
import { mapState, mapActions, mapMutations } from 'vuex' export default { data() { return {
localCount: 2
} }, methods:{ getTodoById(id) { return this.$store.getters.getTodoById(id) }, increment(payload){ //payload能夠爲對象,如:{ amount: 10} this.$store.commit('increment', payload) //對象風格的提交方式 //this.$store.commit({type: 'increment',amount: 10}) }, ...mapMutations([ //mutation 都是同步事務,store.commit('increment'), 任何由 "increment" 致使的狀態變動都應該在此刻完成。 //爲解決異步問題咱們引入action 'increment', // 將 `this.increment()` 映射爲 `this.$store.commit('increment')` //add: 'increment' // 將 `this.add()` 映射爲 `this.$store.commit('increment')` // `mapMutations` 也支持載荷: 'incrementBy' // 將 `this.incrementBy(amount)` 映射爲 `this.$store.commit('incrementBy', amount)` ]), ...mapActions([ 'increment', // 將 `this.increment()` 映射爲 `this.$store.dispatch('increment')` //add: 'increment' // 將 `this.add()` 映射爲 `this.$store.dispatch('increment')` // `mapActions` 也支持載荷: 'incrementBy' // 將 `this.incrementBy(amount)` 映射爲 `this.$store.dispatch('incrementBy', amount)` ]), actionA() { store.dispatch('actionA').then(() => { // ... }) } }, computed:{ //count () { // return this.$store.state.count //} ...mapState({ // 使用對象展開運算符將此對象混入到外部對象中 // 箭頭函數可以使代碼更簡練 count: state => state.count, // 傳字符串參數 'count' 等同於 `state => state.count` countAlias: 'count', // 爲了可以使用 `this` 獲取局部狀態,必須使用常規函數 countPlusLocalState (state) { return state.count + this.localCount } }), doneTodosCount () { return this.$store.state.todos.filter(todo => todo.done).length }, DoneTodos(){ return this.$store.getters.doneTodos }, getDoneTodosCount () { return this.$store.getters.doneTodosCount }, // 使用對象展開運算符將 getter 混入 computed 對象中 ...mapGetters([ 'doneTodosCount', //映射 `this.doneCount` 爲 `store.getters.doneTodosCount` doneCount: 'doneTodosCount' ]) } }
main.jsapi
import Vue from 'vue' import store from './store/' new Vue({ store }).$mount('#app')
使用常量替代 mutation 事件類型在各類 Flux 實現中是很常見的模式。這樣可使 linter 之類的工具發揮做用,同時把這些常量放在單獨的文件中可讓你的代碼合做者對整個 app 包含的 mutation 一目瞭然:cookie
// mutation-types.js export const SOME_MUTATION = 'SOME_MUTATION' // store.js import Vuex from 'vuex' import { SOME_MUTATION } from './mutation-types' const store = new Vuex.Store({ state: { ... }, mutations: { // 咱們可使用 ES2015 風格的計算屬性命名功能來使用一個常量做爲函數名 [SOME_MUTATION] (state) { // mutate state } } })
Mutation 必須是同步函數app
一條重要的原則就是要記住 mutation 必須是同步函數。爲何?請參考下面的例子:異步
mutations: { someMutation (state) { api.callAsyncMethod(() => { state.count++ }) } }
如今想象,咱們正在 debug 一個 app 而且觀察 devtool 中的 mutation 日誌。每一條 mutation 被記錄,devtools 都須要捕捉到前一狀態和後一狀態的快照。然而,在上面的例子中 mutation 中的異步函數中的回調讓這不可能完成:由於當 mutation 觸發的時候,回調函數尚未被調用,devtools 不知道何時回調函數實際上被調用——實質上任何在回調函數中進行的的狀態的改變都是不可追蹤的。async
Vuex 並不限制你的代碼結構。可是,它規定了一些須要遵照的規則:
應用層級的狀態應該集中到單個 store 對象中。
提交 mutation 是更改狀態的惟一方法,而且這個過程是同步的。
異步邏輯都應該封裝到 action 裏面。
只要你遵照以上規則,如何組織代碼隨你便。若是你的 store 文件太大,只需將 action、mutation 和 getter 分割到單獨的文件。
對於大型應用,咱們會但願把 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 # 產品模塊
modules:
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 的狀態
爲何使用getters來訪問數據?
訪問state中數據直接使用this.$store.state.elements是能夠的,但根據業務的需求每每還要作一些業務上的處理,如:state中goods存放的是用戶購買的清單,但此時咱們只須要商品的數量,咱們不須要拿到全部的物品清單,此時咱們就能夠在得到state的過程當中在加上一層邏輯,也就是getters來得到物品數量
vuex存取的數據,在刷新頁面時丟失?
將數據存入cookie,webstorage,當刷新頁面時判斷是否有數據,沒有再去取