애플리케이션 구조
사실 Vuex는 코드 구조를 구성하는 방법에 제한이 없습니다. 반대로 일련의 상위 수준 원칙을 시행합니다.
1. level 상태는 매장 내에서 중앙 집중화됩니다.
2. 상태를 변경하는 유일한 방법은 동기 트랜잭션인 mutation을 제출하는 것입니다.
3. 비동기 로직은 실제로 캡슐화되어야 합니다.
이러한 규칙을 따르는 한 프로젝트 구성 방법은 귀하에게 달려 있습니다. 스토어 파일이 매우 크다면 액션, 뮤테이션, 게터 파일로 분할하세요.
약간 더 복잡한 애플리케이션의 경우 모듈을 사용해야 할 수도 있습니다. 다음은 간단한 프로젝트 구조입니다:
├── index.html
├── main.js
├── api
│ └── ... # 여기에서 API 실행 요청
├── 구성요소
│ ├── App.vue
│ └── ...
└── store
├── index.js
├── actions.js ├── actions.js ├── mutations.js # 루트 변이
└── 모듈
├── cart.js # 장바구니 모듈
└── products .js # 제품 모듈
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
const moduleA = { state: { count: 0 }, mutations: { increment: (state) { // state 是模块本地的状态。 state.count++ } }, getters: { doubleCount (state) { return state.count * 2 } } }
const moduleA = { // ... actions: { incrementIfOdd ({ state, commit }) { if (state.count % 2 === 1) { commit('increment') } } } }
const moduleA = { // ... getters: { sumWithRootCount (state, getters, rootState) { return state.count + rootState.count } } }
// types.js // 定义 getter、 action 和 mutation 的常量名称 // 并且在模块名称上加上 `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 and mutations const todosModule = { state: { todos: [] }, getters: { [types.DONE_COUNT] (state) { // ... } }, actions: { [types.FETCH_ALL] (context, payload) { // ... } }, mutations: { [types.TOGGLE_DONE] (state, payload) { // ... } } }
store.registerModule('myModule', { // ... })
const myPlugin = store => { // 当 store 在被初始化完成时被调用 store.subscribe((mutation, state) => { // mutation 之后被调用 // mutation 的格式为 {type, payload}。 }) }
const store = new Vuex.Store({ // ... plugins: [myPlugin] })
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] })
const myPluginWithSnapshot = store => { let prevState = _.cloneDeep(store.state) store.subscribe((mutation, state) => { let nextState = _.cloneDeep(state) // 对比 prevState 和 nextState... // 保存状态,用于下一次 mutation prevState = nextState }) }
const store = new Vuex.Store({ // ... plugins: process.env.NODE_ENV !== 'production' ? [myPluginWithSnapshot] : [] })
如果你正在使用 vue-devtools,你可能不需要。
Vuex 带来一个日志插件用于一般的调试:
import createLogger from 'vuex/dist/logger' const store = new Vuex.Store({ plugins: [createLogger()] })
createLogger 方法有几个配置项:
const logger = createLogger({ collapsed: false, // 自动展开记录 mutation transformer (state) { // 在记录之前前进行转换 // 例如,只返回指定的子树 return state.subTree }, mutationTransformer (mutation) { // mutation 格式 { type, payload } // 我们可以按照想要的方式进行格式化 return mutation.type } })
日志插件还可以直接通过