Vuex下Store的模塊化拆分實踐

前言

最近的項目用到了 vue.js + vuex + vue-router 全家桶,版本爲 >2.0,在搞Store的時候發現,圈子裏大部分關於vuex的文章都是比較基礎的Demo搭建方式,不多有涉及到比較複雜的模塊化拆分的Store實踐,並且事實上也有朋友在實踐中問到過這方面的內容,vuex自身提供了模塊化的方式,所以在這裏總結一下我本身在項目裏的心得。html

模塊化拆分

vue.js的項目文件結構在這裏就不說了,你們能夠經過vue-cli初始化項目,腳手架會爲你搭建一個start項目的最佳實踐。vue

默認你已經搭架好了一個項目,並且須要創建或者已是一個複雜的Store,可是尚未進行模塊拆分,你能夠嘗試對其進行模塊拆分,固然在一開始你沒必要必定須要這麼作。node

1. 安裝Vuex,創建文件結構

在項目根目錄下安裝vuex:ios

npm install vuex -S

安裝完畢後,在項目的src文件夾下新建一個store文件夾,而且分別在其中新建modules,actions,mutations,getters,constants子文件夾和一個index.js文件。git

目錄結構以下:github

└─ demo/
   ├── build/
   ├── config/
   ├── node_modules/
   ├── src/
   │   ├── assets/
   │   ├── components/
   │   ├── store/
   │   │   ├── actions/ 
   │   │   │   ├──aAction.js
   │   │   │   ├──bAction.js
   │   │   │   └──cAction.js
   │   │   ├── constants/
   │   │   │   └── types.js
   │   │   ├── getters/
   │   │   │   └── aGetter.js
   │   │   ├── modules/
   │   │   │   ├── aModules.js
   │   │   │   ├── bModules.js
   │   │   │   ├── cModules.js
   │   │   │   └── index.js
   │   │   ├── mutations/
   │   │   │   ├── aMutation.js
   │   │   │   ├── bMutation.js
   │   │   │   └── cMutation.js
   │   │   └── index.js
   │   ├── App.vue
   │   └── main.js
   ├── static/
   ├── utils/
   ├── test/
   └── index.html

好了,基本的文件結構大概就是上面?這樣的。vue-router

2. 編寫模塊A

在編寫模塊以前,首先設定一些type類,例如:vuex

types.js

module.exports = keyMirror({

    FETCH_LIST_REQUEST: null,
    FETCH_LIST_SUCCESS: null,
    FETCH_LISR_FAILURE: null
    
})

function keyMirror (obj) {
  if (obj instanceof Object) {
    var _obj = Object.assign({}, obj)
    var _keyArray = Object.keys(obj)
    _keyArray.forEach(key => _obj[key] = key)
    return _obj
  }
}

上面?本身實現keyMirror的方法,你們也可使用下面這個包:
github.com/STRML/keyMirrorvue-cli

keyMirror的做用就是下面這個一個形式?,做用其實也不是很大:npm

Input: {key1: null, key2: null}

Output: {key1: key1, key2: key2}

actions/aAction.js

import { FETCH_LIST_REQUEST, FETCH_LIST_SUCCESS, FETCH_LISR_FAILURE } from  '../constants/types'
import { toQueryString } from '../../utils'
import axios from 'axios'

export const fetchListAction = {
    fetchList ({ commit, state }, param) {
        commit(FETCH_LIST_REQUEST)
        axios.get('http://youdomain.com/list')
          .then(function (response) {
            commit(FETCH_LIST_SUCCESS, {
                data: response.data
            })  
            console.log(response);
          })
          .catch(function (error) {
            commit(FETCH_LIST_FAILURE, {
                error: error
            })
            console.log(error);
          });
    }
}

getters/aGetter.js

export const = fetchListGetter = {
    hotList (state) {
        return state.list.data.slice(0, 10)
    }
}

mutations/aMutation.js

import { FETCH_LIST_REQUEST, FETCH_LIST_SUCCESS, FETCH_LISR_FAILURE } from  '../constants/types'

export const fetchListMutation = {
    [FETCH_LIST_REQUEST] (state) {
        state.isFetching = true
    },
    [FETCH_LIST_SUCCESS] (state, action) {
        state.isFetching = false
        state.data = action.data
        state.lastUpdated = (new Date()).getTime()
    },
    [FETCH_LIST_FAILURE] (state, action) {
        state.isFetching = false
        state.error = action.error
    }
}

modules/aModule.js

import { fetchListAction } from '../actions/aAction'
import { fetchListGetter } from '../getters/aGetter'
import { fetchListMutation } from '../mutations/aMutation'

export const list = {
    state: {
        isFetching: false,
        data: []
    }
    actions: fetchListAction,
    getters: fetchListGetter,
    mutations: fetchListMutation
}

modules/index.js

import { list } from './aModule'

module.exports = {
    list: list
}

3. 掛載store

index.js

import Vue from 'vue'
import Vuex from 'vuex'
import createLogger from 'vuex/dist/logger'
import { list } from './modules'

Vue.use(Vuex)

const store = new Vuex.Store({
  modules: {
    list: list
    
  },
  plugins: [createLogger()],
  strict: process.env.NODE_ENV !== 'production'
})

if (module.hot) {
  module.hot.accept(['./mutations'], () => {
    const newMutations = require('./mutations').default

    store.hotUpdate({
      mutations: newMutations
    })
  })
}

export default store

4. store注入vue實例

main.js

····
import store from './store'

  ···· 


var vue = new Vue({
  store,
 
  ···· 

})

vue.$mount('#app')

5. 在Component中使用

Vuex 提供了組件中使用的mapState,mapAction,mapGetter方法,所以能夠很方便的調用。

Example.vue

<template>

 ·········

</template>
<script>
import { mapState, mapActions, mapGetters } from 'vuex'
module.exports = {
    ·······
    methods: {
        ...mapActions([
            'fetchList'
        ])
    },
    computed: {
        ...mapState{
            list: state => state.list
        },
        ...mapGetters{[
            'hotList'
        ]}
    }
}
</script>
<style>
    ·······
</style>

複用模塊

模塊化拆分以後能夠實現較爲複雜的數據流,特別地,若是對action和mutation稍加改造,就能夠複用模塊:
好比咱們在Example.vue中發起Action:

Example.vue

<template>

 ·········

</template>
<script>
import { mapState, mapActions, mapGetters } from 'vuex'
module.exports = {
    ·······
    mounted () {
        this.fetchList({
            request: 'week'
        })
    },
    methods: {
        ...mapActions([
            'fetchList'
        ])
    },
    computed: {
        ...mapState{
            list: state => state.list
        },
        ...mapGetters{[
            'hotList'
        ]}
    }
}
</script>
<style>
    ·······
</style>

在上面的例子中,咱們在組件掛載完成以後發起了一個fetchList的action,並添加了一個名爲request的參數,這裏給一個week值,也能夠給按照業務須要給monthyear之類的值,接下來對aAction.js作一些修改。

actions/aAction.js

import { FETCH_LIST_REQUEST, FETCH_LIST_SUCCESS, FETCH_LISR_FAILURE } from  '../constants/types'
import { toQueryString } from '../../utils'
import axios from 'axios'

export const fetchListAction = {
    fetchList ({ commit, state }, param) {
        commit(FETCH_LIST_REQUEST, {
            request: param['request']
        })
        axios.get(`http://youdomain.com/${param['request']}list`)
          .then(function (response) {
            commit(FETCH_LIST_SUCCESS, {
                request: param['request']
                data: response.data
            })  
            console.log(response);
          })
          .catch(function (error) {
            commit(FETCH_LIST_FAILURE, {
                request: param['request']
                error: error
            })
            console.log(error);
          });
    }
}

請求成功以後,在 commit()中加入了一個request的參數,這樣Mutation就能夠從裏面獲取相應的參數,最後對aMutation作一些修改。

mutations/aMutation.js

import { FETCH_LIST_REQUEST, FETCH_LIST_SUCCESS, FETCH_LISR_FAILURE } from  '../constants/types'

export const fetchListMutation = {
    [FETCH_LIST_REQUEST] (state, action) {
        state[action.request].isFetching = true
    },
    [FETCH_LIST_SUCCESS] (state, action) {
        state[action.request].isFetching = false
        state[action.request].data = action.data
        state[action.request].lastUpdated = (new Date()).getTime()
    },
    [FETCH_LIST_FAILURE] (state, action) {
        state[action.request].isFetching = false
        state[action.request].error = action.error
    }
}

state加入了[action.request],以區分不一樣的接口數據。

完成以上修改後,只須要在組件調用相應的action時加入不一樣的參數,就能夠調用相同類型但數據不一樣的接口。

總結

以上是我在Vuex實踐中總結的一些東西,分享給你們,若是有不合理或者錯誤❌的地方,也但願各位老司機不吝賜教??,有機會多交流。

微信號:pasturn
Github:https://github.com/pasturn

相關文章
相關標籤/搜索