Vuex 并非限制你的代码结构,而是遵循一些观点:
Vuex actions 和 mutations 很好的地方在于 他们都仅仅是函数。你只需要遵循以上的准则,怎么组织代码就取决于你自己了。最简单的 Vuex 实例甚至只需要在 单个文件 中声明!然而这对于很多项目来说并不够,所以这里有些根据不同应用规模推荐的不同结构。
在简单的项目里,我们可以把 actions 和 mutations 分离到各自的文件:
.
├── index.html
├── main.js
├── components
│ ├── App.vue
│ └── ...
└── vuex
├── index.js # exports the vuex instance
├── actions.js # exports all actions
└── mutations.js # exports all mutations
一个真实的 TodoMVC 例子.
For any non-trivial app, we probably want to further split Vuex-related code into multiple "modules" (roughly comparable to "stores" in vanilla Flux), each dealing with a specific domain of our app. Each module would be managing a sub-tree of the state, exporting the initial state for that sub-tree and all mutations that operate on that sub-tree:
???
├── index.html
├── main.js
├── api
│ └── ... # abstractions for making API requests
├── components
│ ├── App.vue
│ └── ...
└── vuex
├── actions.js # exports all actions
├── index.js
├── modules
│ ├── cart.js # state and mutations for cart
│ └── products.js # state and mutations for products
└── mutation-types.js # constants
一个典型的模块:
// vuex/modules/products.js
import { RECEIVE_PRODUCTS, ADD_TO_CART } from '../mutation-types'
// initial state
export const productsInitialState = []
// mutations
export const productsMutations = {
[RECEIVE_PRODUCTS] (state, products) {
state.products = products
},
[ADD_TO_CART] ({ products }, productId) {
const product = products.find(p => p.id === productId)
if (product.inventory > 0) {
product.inventory--
}
}
}
在 vuex/index.js
里我们把多个模块集合在一起来创建 Vuex 实例:
import Vue from 'vue'
import Vuex from '../../../src'
import * as actions from './actions'
// import parts from modules
import { cartInitialState, cartMutations } from './modules/cart'
import { productsInitialState, productsMutations } from './modules/products'
Vue.use(Vuex)
export default new Vuex({
// ...
// combine sub-trees into root state
state: {
cart: cartInitialState,
products: productsInitialState
},
// mutations can be an array of mutation definition objects
// from multiple modules
mutations: [cartMutations, productsMutations]
})
Since all modules simply export objects and functions, they are quite easy to test and maintain. You are also free to alter the patterns used here to find a structure that fits your preference.
Note that we do not put actions into modules, because a single action may dispatch mutations that affect multiple modules. It's also a good idea to decouple actions from the state shape and the implementation details of mutations for better separation of concerns. If the actions file gets too large, we can turn it into a folder and split out the implementations of long async actions into individual files.
For an actual example, check out the Shopping Cart Example.
???
在大型项目中,多个组件使用同一个基于 Vuex state 的 computed 属性是有可能的。由于 computed getters 只是普通函数,你可以把它们独立在另一个文件里,以实现共享:
// getters.js
import vuex from './vuex'
export function filteredTodos () {
return vuex.state.messages.filter(message => {
return message.threadID === vuex.state.currentThreadID
})
}
// in a component...
import { filteredTodos } from './getters'
export default {
computed: {
filteredTodos
}
}
这非常像 Getters in NuclearJS.