Vue - 用小白的學習方式去掌握 Vuex 使用

Vuex 是什麼

Vuex是什麼javascript

  • 一個專爲 Vue.js 應用程序開發的響應式狀態管理模式.

狀態管理是什麼?

從我我的角度來看,狀態能夠指代數據。而狀態管理也就能夠看做數據管理,主要是用於分層解耦。html

Vuex中狀態管理能夠看做是全局變量,這個變量能夠經過state取出變量映射到view中,也能夠根據用戶的輸入actions改變該變量vue

響應式是什麼?

從我我的角度來看,響應式就是自適應。java

Vuex中響應式是指數據(狀態)的改變可以及時的全部數據變動爲最新的數據。git

不用 Vuex 也是能夠的

  • 從父組件一層一層將數據傳遞給子組件(麻煩)
  • 經過 EventBus 的訂閱/發佈模式實現數據數據傳遞

可看這篇文章介紹:什麼狀況下我應該使用 Vuexgithub

使用

安裝

npm 安裝web

npm install vuex --save

知識儲備

全局 store

參考:shoppint-cart 示例
store 目錄下建立index.jsvuex

import Vue from 'vue'
import Vuex from 'vuex'
import cart from './modules/cart'
import products from './modules/products'
import createLogger from '../../../src/plugins/logger'

Vue.use(Vuex)

const debug = process.env.NODE_ENV !== 'production'

export default new Vuex.Store({ 
 
   
  // 注入其它模塊的 store
  modules: { 
 
   
    cart,
    products
  },
  strict: debug,
  plugins: debug ? [createLogger()] : []
})

app.js中注入store,如:npm

import Vue from 'vue'
import App from './components/App.vue'
import store from './store'
import { 
 
    currency } from './currency'

Vue.filter('currency', currency)

new Vue({ 
 
   
  el: '#app',
  store, // 全局注入
  render: h => h(App)
})

如在counter組件中經過this.$store去使用緩存

this.$store.commit('increment')

State

用於聲明數據。

computed 計算屬性

對於任何複雜邏輯,你都應當使用計算屬性。

例以下面的示例中,第二個 message ,若是咱們要在 view 中寫也是能夠,可是會比較複雜,以下:

<p>Computed reversed message: "{
  
  
   
   
            
   

  { message.split('').reverse().join('') }}"</p>

那麼咱們能夠將該複雜寫法經過計算屬性封裝成一個方法,直接調用該方法對象便可。
示例:

<div id="example">
  <p>Original message: "{ 
 
   { message }}"</p>
  <p>Computed reversed message: "{ 
 
   { reversedMessage }}"</p>

  <!-- 在 Vuex 中若是不用計算屬性,咱們須要這麼寫 -->
  <p>Computed reversed message: "{ 
 
   { this.$store.state.counter.message.split('').reverse().join('') }}"</p>

</div>

var vm = new Vue({ 
 
   
  el: '#example',
  data: { 
 
   
    message: 'Hello'
  },
  computed: { 
 
   
    // 計算屬性的 getter
    reversedMessage: function () { 
 
   
      // `this` 指向 vm 實例
      // 使用 vuex 則可經過 $store 取到數據以後再轉換,以下
      // return this.$store.state.counter.message.split('').reverse().join('')
      return this.message.split('').reverse().join('')
    }
  }
})

輸出結果:

Original message: "Hello"

Computed reversed message: "olleH"

mapState 輔助函數

當一個組件須要獲取多個狀態的時候,將這些狀態都聲明爲計算屬性會有些重複和冗餘。爲了解決這個問題,咱們可使用 mapState 輔助函數幫助咱們生成計算屬性。

輔助函數,用於簡化this.$store.state,示例以下:

<template>
  <div>
    <!-- 直接使用 -->
    Clicked: { 
 
   { 
 
    $store.state.counter.count }} times.
    <br>
    <!-- 使用 Vuex mapState -->
    mapState使用: { 
 
   { 
 
    count }} times.
  </div>
</template>

<script>
// 在單獨構建的版本中輔助函數爲 Vuex.mapState
import { 
 
    mapState } from 'vuex'

export default { 
 
   

  computed:{ 
 
   
    ...mapState({ 
 
   
      count: state => state.counter.count
    }),
  },

  methods: { 
 
   
  }
}
</script>

有時候咱們須要從 store 中的 state 中派生出一些狀態。
如上面的字符串反轉功能就是派生出來的,咱們可使用Getters去實現。

Getters

能夠認爲是 store 的計算屬性。getter 的返回值會根據它的依賴被緩存起來,且只有當它的依賴值發生了改變纔會被從新計算。

經過一個示例來看一下getters如何使用。
Counter.vue文件以下:

<template>
  <div>
    <p>hello 字符串反轉:{ 
 
   { 
 
    reverseStr }}</p>
    <p>getter 獲取 todo done: { 
 
   { 
 
    doneTodosCount }}</p>
    <p>傳入 getters 作參數:{ 
 
   { 
 
    doneTodosCount }}</p>
    <p>直接訪問:{ 
 
   { 
 
    doneTodos }}</p>
  </div>
</template>

<script>
// 在單獨構建的版本中輔助函數爲 Vuex.mapGetters
import { 
 
     mapGetters } from "vuex";

export default { 
 
   
  computed: { 
 
   
    // 因爲使用了命名空間,所以須要加上,不然獲取反轉的字符串如: reverseStr:'counter/reverseStr'
    ...mapGetters('counter',{ 
 
   
      reverseStr: "reverseStr",
      doneTodosCount: "doneTodosCount",
      doneTodos: "doneTodos",
    }),
  },

};
</script>

counter.js文件以下:

const state = () => ({ 
 
   
    message: 'hello',
    todos: [{ 
 
   
            id: 1,
            text: '寫日報',
            done: true
        },
        { 
 
   
            id: 2,
            text: '看一篇英文文章',
            done: false
        }
    ]
})

// getters
const getters = { 
 
   
    doneTodos: state => { 
 
    
        return state.todos.filter(todo => todo.done)
    },
    doneTodosCount: (state, getters) => { 
 
    // 傳入 getters 作參數
        return getters.doneTodos.length
    },
    reverseStr: state => { 
 
   
        return state.message.split('').reverse().join('')
    }
}

export default { 
 
   
    namespaced: true,
    state,
    getters,
}

Mutations

經過提交 mutation 的方式,而非直接改變 store.state.count
其實也就是經過方法的方式去操做數據。並且Mutation 必須是同步函數,若是是異步函數請使用下一節的Action

看個示例:每次點擊increment文本+2,每次點擊decrement文本-2
Counter.vue文件以下

<template>
  <div>
     <p @click="mIncrement">mutations 獲取 increment: { 
 
   { 
 
    mutationsCount }}</p>
     <p @click="mDecrement">mutations 獲取 decrement: { 
 
   { 
 
    mutationsCount }}</p>
  </div>
</template>

<script>
// 在單獨構建的版本中輔助函數爲 Vuex.mapState
import { 
 
    mapState } from "vuex";

export default { 
 
   
  computed: { 
 
   
    ...mapState({ 
 
   
      count: (state) => state.counter.count,
      mutationsCount: (state) => state.counter.mutationsCount,
    }),
  },

  methods: { 
 
   
    mIncrement() { 
 
   
      this.$store.commit("counter/mIncrement",2);
    },
    mDecrement() { 
 
   
      this.$store.commit("counter/mDecrement",{ 
 
   
        amount:2
      });
    },

  },
};
</script>

counter.js以下:

const state = () => ({ 
 
   
    mutationsCount:0,
})
const mutations = { 
 
   

    mIncrement(state, n) { 
 
   
        state.mutationsCount += n
    },
    // 經過對象傳遞
    mDecrement(state,payload) { 
 
   
        state.mutationsCount -= payload.amount
    },
}

export default { 
 
   
    namespaced: true,
    state,
    mutations
}

Actions

Action 相似於 mutation,不一樣在於:

  • Action 提交的是 mutation,而不是直接變動狀態。
  • Action 能夠包含任意異步操做。

counter計數器示例:
Counter.vue文件以下:

<template>
  <div>
    Clicked: { 
 
   { 
 
    $store.state.counter.count }} times.
    <br />
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
   
  </div>
</template>

<script>
// 在單獨構建的版本中輔助函數爲 Vuex.mapState
import { 
 
    mapState, mapGetters } from "vuex";

export default { 
 
   
  computed: { 
 
   
    ...mapState({ 
 
   
      count: (state) => state.counter.count,
    }),
  },

  methods: { 
 
   

    increment() { 
 
   
      this.$store.dispatch("counter/increment");
    },
    decrement() { 
 
   
      this.$store.dispatch("counter/decrement");
    },
  },
};
</script>

counter.js文件以下:

const state = () => ({ 
 
   
    count: 0,
})
const mutations = { 
 
   
    increment(state) { 
 
   
        state.count++
    },
    decrement(state) { 
 
   
        state.count--
    },
}

const actions = { 
 
   
    increment: ({ 
 
   
        commit
    }) => commit('increment'),
    decrement: ({ 
 
   
        commit
    }) => commit('decrement'),
}

export default { 
 
   
    namespaced: true,
    state,
    actions,
    mutations
}

Modules

也就是分模塊。
例如Counter組件,在 store/modules下建立counter.js用於處理store相關的數據,而Counter.vue組件頁面就正常寫便可。
接着在store/目錄下的 index.js添加 module的注入。具體可看上文的store全局注入。

購物車示例

對照上面的分析,你能夠很容易看懂Vuex examples 中的 shoppint-cart示例了
shoppint-cart 示例地址

該示例是經過shop.js模擬數據,而後將products 和 cart組件注入全局 store
而後ProductList.vue展現shop.js中的商品列表,而ShoppingCart.vue展現購物車數據。

END~

本文同步分享在 博客「_龍衣」(CSDN)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索