Vuex

Vuex 是一個專爲Vue.js應用程序開發的狀態管理模式。它採用集中式存儲管理應用的所有組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。Vuex 和單純的全局對象有以下兩點不同

  • Vuex 的狀態存儲是響應式的。當 Vue 組件從 store 中讀取狀態的時候,若 store 中的狀態發生變化,那麼相應的組件也會相應地得到高效更新。
  • 你不能直接改變 store 中的狀態。改變 store 中的狀態的唯一途徑就是顯式地提交 (commit) mutation。這樣使得我們可以方便地跟蹤每一個狀態的變化,從而讓我們能夠實現一些工具幫助我們更好地瞭解我們的應用。

回顧組件

Index.vue

<template>
    <div id="app">
        <product-list-one :products="products"></product-list-one>
        <product-list-two :products="products"></product-list-two>
    </div>
</template>

<script>
import ProductListOne from './ProductListOne'
import ProductListTwo from './ProductListTwo'
export default {
    name: 'Index',
    components: {
        'product-list-one': ProductListOne,
        'product-list-two': ProductListTwo
    },
    data(){
        return {
            products: [
                {name: 'apple', price: 200},
                {name: 'pear', price: 140},
                {name: 'banana', price: 20},
                {name: 'mango', price: 10},
            ]
        }
    }
}
</script>

ProductListOne

<template>
    <div>
        <h2>1</h2>
        <ul>
            <li v-for="product in products" :key="product+Math.random()*Date.now()">
                <span class="name">{{product.name}}</span>
                <span class="price">{{product.price}}</span>
            </li>
        </ul>
    </div>
</template>

<script>
export default {
    props: ['products'],
    data(){
        return {

        }
    }
}
</script>

<style scoped>
    div{
        font-weight: bold;
        color: #f0f;
    }
</style>

ProductListTwo

<template>
    <div>
        <h2>2</h2>
        <ul>
            <li v-for="product in products" :key="product+Math.random()*Date.now()">
                <span class="name">{{product.name}}</span>
                <span class="price">{{product.price}}</span>
            </li>
        </ul>
    </div>
</template>

<script>
export default {
    props: ['products'],
    data(){
        return {

        }
    }
}
</script>

store.js

state

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export const store = new Vuex.Store({
    state: {
        products: [
            {name: 'apple', price: 200},
            {name: 'pear', price: 140},
            {name: 'banana', price: 20},
            {name: 'mango', price: 10},
        ]
    }
})

main.js

import Vue from 'vue'
import App from './App'
import router from './router'
import {store} from './store'

new Vue({
  el: '#app',
  router,
  store,
  components: {App},
  template: '<App/>'
})

Index.vue

<template>
    <div id="app">
        <product-list-one></product-list-one>
        <product-list-two></product-list-two>
    </div>
</template>

<script>
import ProductListOne from './ProductListOne'
import ProductListTwo from './ProductListTwo'
export default {
    name: 'Index',
    components: {
        'product-list-one': ProductListOne,
        'product-list-two': ProductListTwo
    },
    data(){
        return {
            // 把數據移到store的state裏了
        }
    }
}
</script>

ProductListOne.vue

<template>
    <div>
        <h2>1</h2>
        <ul>
            <li v-for="product in products" :key="product+Math.random()*Date.now()">
                <span class="name">{{product.name}}</span>
                <span class="price">{{product.price}}</span>
            </li>
        </ul>
    </div>
</template>

<script>
export default {
    computed: {
        products(){
            // 接收store的數據
            return this.$store.state.products;
        }
    },
    data(){
        return {
            
        }
    }
}
</script>

改變名字,價格打折
ProductListTwo.vue

v-for="product in saleProducts"

computed: {
    saleProducts(){
        return this.$store.state.products.map(product=>{
          return  {
              name: `**${product.name}**`,
              price: product.price/2
            }
        });
    }
}

如果在組件ProductListOne.vue也要改名打折,複製即可,但成百上千個組建也需要呢?就用到getters了。

getters

store.js

getters: {
    saleProducts(state){
        return state.products.map(product=>{
          return  {
              name: `**${product.name}**`,
              price: product.price/2
            }
        });
    }
}

ProductListOne.vue或其他需要用到的組件

computed: {
    saleProducts(){
        return this.$store.getters.saleProducts;
    }
}

Mutations

store.js

mutations: {
    reducePrice: state=>{
        state.products.forEach(p=>{
            p.price -=1;
        })
    }
}

組件的methods

<button @click="reductPrice">降價</button>

reducePrice(){
    this.$store.commit('reducePrice')
}

Actions

如果把mutations改爲異步,即

mutations: {
    reducePrice: state=>{
        setTimeout(function(){
            state.products.forEach(p=>{
                p.price -=1;
            })
        },3000)
    }
}

這樣在頁面上呈現效果(3000ms後)和Vue Devtools Vuex調試(立即)不一致。但是在actions裏面就可以了。

actions: {
    reducePrice: context => {
        setTimeout(function(){
            context.commit('reducePrice'); // mutations的reducePrice
        },3000)
    }
}
傳參數

mutations 和 actions

mutations: {
    reducePrice: (state,num)=>{
        state.products.forEach(p=>{
            p.price -=num;
        })
    }
},
actions: {
    reducePrice: (context,num) => {
        setTimeout(function(){
            context.commit('reducePrice',num); // mutations的reducePrice
        },3000)
    }
}

組件

<button @click="reducePrice(4)">降價</button>
4是實參

methods: {
    reducePrice(amount){ // amount是形參
        this.$store.dispatch('reducePrice',amount)
    }
}

如果 actions 裏面有多個方法呢,不可能完全在methods裏面列舉,就可以在組件中這樣解決。

import {mapGetters, mapActions} from 'vuex'

export default{
    computed: {
        ...mapGetters(['saleProducts'])
    },
    methods: {
        ...mapActions(['reducePrice'])
    }
}

https://vuex.vuejs.org/zh/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章