[vue]初探vue生態核心插件Vuex


為什么會有 Vuex 這個東西 ?

現代前端框架主要解決的是 事件 -> 狀態 -> UI 將傳統前端在兩個過程的代碼剝離出來,變得更加容易維護;

vue的聲明式渲染,解決了 狀態 和 UI 的同步問題,從而使我們不需要由於狀態發生改變去寫大量的命令式改變 dom 的代碼。

而類似於 vuex 這類狀態管理的庫,則解決了 事件 -> 狀態 這個過程的維護問題。這類庫所做的事情就是管理從 事件源映射到狀態變化 這個過程(將這個映射過程從視圖組件中剝離出來,組織好這一部分的代碼,在組件外部進行狀態的管理)

具體表現就是一個全局的數據中心 store 配置,每個組件進行更新的時候就通知數據中心,數據中心改變后,再去觸發每個調用它的組件進行更新(這種更新是響應式的);幾個核心概念就是 mutations里的方法可以直接 mutatestore 中的狀態,並且 mutation 過程必須同步的,需要通過 commit 去觸發;而 actions 則允許異步的操作,通過 commit 去觸發 mutation ,達到間接修改 store的目的,action 本身需要通過 disptch去觸發。

Vuex與全局對象的區別

其實,vuex 與全局對象有一定的共同之處,那就是狀態會被全局共享,無論是嵌套多少組件…

每一個 Vuex 應用的核心就是 store(倉庫)。“store”基本上就是一個容器,它包含着你的應用中大部分的狀態 (state)。Vuex 和單純的全局對象有以下兩點不同:

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

Vuex常見的應用場景

管理狀態與共享狀態

應用簡單時,可以使用 propevent 來完成 父子組件 的通信。使用 global event bus(event bus)來實現 簡單的非父子組件之間的跨組件 通信。但對於 多層級組件嵌套 等較為復雜的場景,使用 vuex 能更好地應對。(使用 event bus 的缺點是當狀態較復雜,調用組件非常多,要挨個依次通知所有組件更新;每個組件對這個組件進行的狀態更新都要通知監聽該事件的所有組件;這樣會變得非常復雜)(你通知我, 我通知你, 你通知他, 他通知我 ... 大家之間是直接相互作用的)

vuex 狀態管理模型,擁有一個統一的數據中心Store,Store用來維護狀態數據;每個組件進行更新的時候就通知數據中心,數據中心改變后,再去統一觸發每一個調用它的組件進行更新(相當於由數據中心來統籌狀態變化以及狀態變化的分發,而不是由每個vue組件直接去操作state) (有點類似於中介者模式, 大家把所有各種類型的信息都反饋給中介, 然后再由中介分發給訂閱了某個類型信息的用戶)

圖解圖解

vuex 是通過將 state 作為數據中心,各個組件 共享 state 來實現跨組件通信的, 此時的數據完全獨立於組件。(點擊不同模塊的操作,不再需要去發送亂七八糟的事件, 只是去調用事件中心里的 mutation 動作, 從而實現模塊間共享狀態的功能)

需要構建一個中大型單頁應用時,很可能會考慮如何更好地 在組件外部 管理狀態

vuex更多地用於解決 跨組件通信 (多層嵌套組件之間的通信問題)以及作為 數據中心集中式存儲數據 (管理應用中錯綜復雜的狀態關系)

vuex 作為數據存儲中心

vuexstate在單頁應用的開發中本身具有一個 數據庫 的作用,可以將組件用到的數據存儲在 state中,並在 actions中封裝數據讀寫的邏輯。目前主要有兩種數據會使用 vuex進行管理

  1. 組件之間 全局共享 的數據
  2. 通過后端異步請求的數據

實際項目開發中更多的是用到第二種,即把通過后端異步請求的數據都納入 vuex 狀態管理,在 actions 中封裝數據的增刪改查等邏輯,這樣可以在一定程度上對前端的邏輯代碼進行分層,使組件中的代碼更多地關注頁面交互與數據渲染等 視圖層 的邏輯,而異步請求與狀態數據的持久化等則交由 vuex 管理

一般全局數據,會使用到 vuex 來管理。比如 用戶數據,系統數據 等,這些數據很多組件中都會使用,我們當然可以每次使用的時候都去請求,但是出於程序員的“潔癖”、“摳”等等優點,還是希望一次請求,到處使用。

這時候很自然的想到存儲在 localStorage 中,但是有個問題是,這些數據可能會變,如果沒能及時 同步 的話,就會用到不正確的數據,即使做了數據同步,但是 localStorage 中的數據不是響應式的,不能自動更新使用到這些數據的地方。這時候就想要開始使用 vuex了。

Vuex代碼的組織方式

vue-router 類似,有非模塊化寫法與模塊化寫法(其實無論何種寫法本質上是一樣的,目的就是導出一份 router或者 store 的配置數據)

以管理 count 與 用戶信息 userinfo 為例,介紹 vuex代碼的組織方式

核心概念 state,getter,mutation,action,module

vuex 需要遵守的規則

應用層級的狀態應該集中到 單個 store 對象中

mutation是直接操作state的方法(唯一能改變狀態的方法),過程要求必須同步

action 通過commit去觸發mutation,從而間接修改狀態,優點是允許異步邏輯,

非模塊化寫法
// 1.安裝 vuex

// 2.在入口文件中引入
// main.js
import Vuex from 'vuex'

// 3.Vue使用 vuex 插件
Vue.use(Vuex)

// 4.生成數據管理中心 store
const store = new Vuex.Store({
    state: {
        userinfonull// 需要給定初始值
        count: 0
    },
    // 直接通過mutation方法來mutate操作state; 只能以同步的方式; mutation方法需要通過commit來觸發
    mutations: {
        userinfofunction (state, payload{
              state.userinfo = options
            localStorage.userinfo = JSON.stringify(state.userinfo)
        },
        incrementfunction (state, payload{
            state.count += payload.amount
        }
    },
    // 通過commit觸發mutations里的mutation方法, 以此間接修改 state; 允許異步操作;action方法需要通過dispatch來觸發
    actions: {
        incrementfunction (context, payload{
            context.commit('increment', payload)
        },
        incrementAsyncfunction (context{
            // 異步請求數據
            setTimeout(() => {
                var amount = 10// 模擬異步請求得到數據
                context.commit('increment', { amount })
            }, 1000)
        },
        async userinfo (context) {
            let response = await getUserInfo() // 異步請求后端數據 方法需要 import
            if (response.ok) {
                let json = await response.json()
                context.commit('userinfo', json)
            }
        }
    },
    getters: {// 處理、過濾數據

    }
})

// 5.通過 store 配置參數注入狀態管理,從而任何組件可通過 this.$store 訪問狀態中心
new Vue({
    el'#app',
    store, // (*)
    render: function (h{
        return h(App)
    }
})
模塊化寫法
// 1.安裝vuex

// 2.引入
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
// import ...

// 3.Vue使用 vuex 插件
Vue.use(Vuex)

// 4.分模塊生成數據管理中心
// 配置 userinfo 狀態模塊 (還能再單獨拆出一個文件,然后import進來)
const moduleA = {
    state: {
        userinfonull // 需要初始化響應式數據
    },
    mutations: {
        userinfofunction (state, options{
            state.userinfo = options
            localstorage.userinfo = JSON.stringify(state.userinfo)
        }
    },
    actions: {
        async userinfo (context) {
            async userinfo (context) {
                let response = await response.json()
                if (response.ok) {
                    let json = await response.json()
                    context.commit('userinfo', json)
                }
            }
        },
        getters: {// 處理、過濾數據

        }
    }
}

// 配置 count 狀態模塊 (還能再單獨拆出一個文件,然后import進來)
const moduleB = {
    state: {
        count1,
    },
    mutations: {
        increment:function (state, payload{
            state.count += payload
        },
    },
    actions: {
        incrementfunction (context, payload{
              context.comit('increment', payload)  
        },
          incrementAsyncfunction (context{
            // 異步請求數據
            setTimeout(() => {
                var amount = 10// 模擬異步請求得到數據
                context.commit('increment', { amount })
            }, 1000)
        },  
    },
    getters: {
        doubleCount (state) {
            return state.count * 2
        }
    }
}

// 5.導出一份 store 的配置
export default new Vuex.Store({
    modules: { // 這里與非模塊化寫法有點不一樣;原來整個對象是一份配置...
        a: moduleA,
        b: moduleB,
    }
})

// store.state.a // -> moduleA 的狀態
// store.state.b // -> moduleB 的狀態

// 6.在根腳本 main.js 中引入 store 配置
import store from './store'
...
// 並通過 store 配置參數注入狀態管理,從而任何組件可通過 this.$store 訪問狀態中心
new Vue({
    el'#app',
    router,
    store,
    renderfunction (h{
        return h(App);
    }
});

在不同組件中使用或操作狀態

// 根組件
// App.vue
// 在生命周期中觸發全局共享數據的獲取
...
mounted () {
    if (!this.$store.state.userinfo) { // this.$store.state.a.userinfo 模塊化寫法的話
        this.$store.dispatch('userinfo')
    }
}

// 使用 state 的數據
computed: {
    userinfo () {
        return this.$store.state.userinfo
        // return this.$store.state.a.userinfo // 模塊化寫法的話
    },
    count () {
        return this.$store.state.count
        // return this.$store.state.b.count // 模塊化寫法的話
    }
}
// 子組件
// NavBar.vue
...
// 改變 state 的數據
methods: {
    // 使用 commit 觸發 mutations 中的 mutation 方法,直接修改 state 中的數據
    addOne () {
        this.$store.commit('increment', { amountthis.price })
    },
    // 使用 dispatch 觸發 actions 中的 action 方法;異步修改 state 中的數據
    addTenAsync () {
        this.$store.dispatch('incrementAsync')
    }
}

// 使用 state 的數據
computed: {
    userinfo () {
        return this.$store.state.userinfo
        // return this.$store.state.a.userinfo // 模塊化寫法的話
    }
}
// 路由頁面組件
// Manage.vue
...
// 改變 state 的數據
methods: {
    addTwo () {
        this.$store.commit('increment', { amountthis.price })
    }
}

// 使用 state 的數據
computed: {
    count () {
        return this.$store.state.count
        // return this.$store.state.b.count // 模塊化寫法的話
    }
},

總之,使用了 vuex 來管理狀態,點擊不同模塊的操作,不再需要去發送亂七八糟的事件, 只是去調用事件中心里的 mutation 動作, 從而實現模塊間共享狀態的功能;修改一處,全局共享(無論是組件還是路由頁面組件都能同步)

最后,再看看 vuex 官網的這張說明圖,是不是更加清晰了呢!

虛線綠框里即vuex做的事虛線綠框里即vuex做的事

-項目地址- vuex-demo


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM