Open SuperLucyFight opened 8 years ago
由于使用一个单一的状态树,我们的应用程序的所有状态都包含在一个大的对象中。然而,随着我们的应用程序规模的增长,store可能会变得非常臃肿。
为了解决上述问题,vuex允许我们将我们的存储模块为 modules。每一个module 能包含它自己的 state、 mutations、 actions、 getters 甚至嵌套的modules —— 它的分形一路下来:
const moduleA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: { ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA's state
store.state.b // -> moduleB's state
在一个module的 mutations 和 getters内, 收到的第一个参数将是 the module's local state。
const moduleA = {
state: { count: 0 },
mutations: {
increment: (state) {
// state is the local module state
state.count++
}
},
getters: {
doubleCount (state) {
return state.count * 2
}
}
}
同样,在module actions内, context.state
将暴露 local state,并且 root state 将作为context.rootState
被暴露。
const moduleA = {
// ...
actions: {
incrementIfOdd ({ state, commit }) {
if (state.count % 2 === 1) {
commit('increment')
}
}
}
}
同样,在 module getters,内, root state 将被暴露为第三个参数:
const moduleA = {
// ...
getters: {
sumWithRootCount (state, getters, rootState) {
return state.count + rootState.count
}
}
}
注意在modules 内的actions、mutations 和getters 仍然注册在全局命名空间下——这允许多个模块的相同mutation/action反应。你可以命名空间模块,资产自己来避免他们名字以前缀或后缀的冲突。也许你应该你正在写一个可重用的vuex模块将被用在未知的环境中。例如,我们要创建一个`todNote‘的module:
// types.js
//定义getters, actions 和 mutations 的名字作为常量
// 并且他们以module名字 `todos`作为前缀
export const DONE_COUNT = 'todos/DONE_COUNT'
export const FETCH_ALL = 'todos/FETCH_ALL'
export const TOGGLE_DONE = 'todos/TOGGLE_DONE'
// modules/todos.js
import * as types from '../types'
// 使用前缀名字定义getters, actions 和 mutations
const todosModule = {
state: { todos: [] },
getters: {
[types.DONE_COUNT] (state) {
// ...
}
},
actions: {
[types.FETCH_ALL] (context, payload) {
// ...
}
},
mutations: {
[types.TOGGLE_DONE] (state, payload) {
// ...
}
}
}
在 store被创建之后,你可以通过 store.registerModule
方法注册一个 module :
store.registerModule('myModule', {
// ...
})
module的 state 将被暴露作为 store.state.myModule
。
动态注册 module 使其他的Vue插件通过整个应用的store一个附加module 利用Vuex 管理state成为可能。例如, vuex-router-sync
/使 vue-router 和vuex结为整体在一个动态的连接模块中通过管理项目的路由状态 。
你也可以用store.unregisterModule(moduleName)
删除动态注册的模块。注意,您不能用此方法静态模块(在存储时的创建声明)。
接受插件选项,为每个变更公开钩子。一个vuex插件是一个简单的函数,接收store 作为唯一的参数:
const myPlugin = store => {
// called when the store is initialized
store.subscribe((mutation, state) => {
// called after every mutation.
// The mutation comes in the format of { type, payload }.
})
}
并且像这样能被使用:
const store = new Vuex.Store({
// ...
plugins: [myPlugin]
})
插件不允许直接变更状态 ——和你的components类似,他们仅仅能触发改变通过提交变更。
通过提交突变,一个插件可以用于将数据源同步到store。 举例, 同步一个WebSocket数据源到 store (这只是一个例子,现实中的createPlugin
功能可以采取一些额外的选项对于较复杂的任务):
export default function createWebSocketPlugin (socket) {
return store => {
socket.on('data', data => {
store.commit('receiveData', data)
})
store.subscribe(mutation => {
if (mutation.type === 'UPDATE_DATA') {
socket.emit('update', mutation.payload)
}
})
}
}
const plugin = createWebSocketPlugin(socket)
const store = new Vuex.Store({
state,
mutations,
plugins: [plugin]
})
有时插件可能想收到一个state的 "snapshots",并对突变后的状态与前突变状态进行了比较 。 要实现这一目标,您将需要在状态对象上执行一个深拷贝:
const myPluginWithSnapshot = store => {
let prevState = _.cloneDeep(store.state)
store.subscribe((mutation, state) => {
let nextState = _.cloneDeep(state)
// compare prevState and nextState...
// save state for next mutation
prevState = nextState
})
}
插件仅在开发过程中使用状态快照。 使用WebPACK或者Browserify的时候,我们可以让我们的构建工具为我们处理:
const store = new Vuex.Store({
// ...
plugins: process.env.NODE_ENV !== 'production'
? [myPluginWithSnapshot]
: []
})
该插件将被默认使用。 对于生产环境,你必须在最后的构建中用Webpack 的DefinePlugin 或者 Browserify 的 envify 来转换 process.env.NODE_ENV !== 'production'
的值为tfalse
。
如果你使用 vue-devtools 你也许不需要这个。
Vuex有一个 logger 插件对于常见的调试使用:
import createLogger from 'vuex/dist/logger'
const store = new Vuex.Store({
plugins: [createLogger()]
})
createLogger
函数需要几个options:
const logger = createLogger({
collapsed: false, // 自动扩展记录的突变
transformer (state) {
// 在记录它之前变换状态。
//例如,只返回一个特定的子树
return state.subTree
},
mutationTransformer (mutation) {
// 变更的记录以这种格式 { type, payload }
// 我们可以格式化它任何我们想要的方式
return mutation.type
}
})
日志文件也可以包括直接通过<script>
标签,并将全局地暴露 createVuexLogger
函数。
注意Logger插件产生状态的快照,所以只有在发展时用它。
安装
直接下载 / CDN
源码:https://unpkg.com/vuex
Unpkg.com 提供基于npm的cdn链接。 上面的链接总是指向npm能安装的最新版本。你也可以使用一个特定版本或者标签,比如https://unpkg.com/vuex@2.0.0。
放vuex.js于 Vue.js之后,并且它会自动安装。
NPM安装
当使用一个模块系统,你必须显式地安装vuex通过Vue.use()。
当使用全局脚本标签时,你不需要这样做。
Dev Build
如果你想使用最新的开发版本,你将不得不直接从github上克隆并且构建。