애플리케이션 구조
사실 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모듈 로컬 상태모듈의 mutations 및 getters 메소드가 전달하는 첫 번째 매개변수는 모듈의 로컬 상태입니다.
const moduleA = { state: { count: 0 }, mutations: { increment: (state) { // state 是模块本地的状态。 state.count++ } }, getters: { doubleCount (state) { return state.count * 2 } } }마찬가지로 모듈의 작업에서 context.state는 로컬 상태를 노출하고 context.rootState는 루트 상태를 노출합니다.
const moduleA = { // ... actions: { incrementIfOdd ({ state, commit }) { if (state.count % 2 === 1) { commit('increment') } } } }모듈의 getter에서는 루트 상태도 세 번째 매개변수로 노출됩니다.
const moduleA = { // ... getters: { sumWithRootCount (state, getters, rootState) { return state.count + rootState.count } } }네임스페이스 모듈 내의 액션, 변이 및 게터는 여전히 전역 네임스페이스에 등록되어 있습니다. 여러 모듈이 동일한 돌연변이/작업 유형에 응답할 수 있습니다. 이름 충돌을 방지하기 위해 모듈 이름에 접두사 또는 접미사를 추가하여 네임스페이스를 설정할 수 있습니다. Vuex 모듈이 재사용 가능하고 실행 환경을 알 수 없는 경우 이 작업을 수행해야 합니다. 거리, 할일 모듈을 생성하고 싶습니다:
// 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) { // ... } } }동적 모듈 등록스토어를 사용하여 스토어에서 생성할 수 있습니다. .registerModule 메소드 그런 다음 모듈을 등록합니다:
store.registerModule('myModule', { // ... })모듈의 store.state.myModule이 모듈의 상태로 노출됩니다. 다른 Vue 플러그인은 애플리케이션 스토어에 모듈을 부착한 후 동적 등록을 통해 Vuex의 상태 관리 기능을 사용할 수 있습니다. 예를 들어, vuex-router-sync 라이브러리는 동적으로 등록된 모듈에서 애플리케이션의 라우팅 상태를 관리하여 vue-router와 vuex를 통합합니다. store.unregisterModule(moduleName)을 사용하여 동적으로 등록된 모듈을 제거할 수도 있습니다. 그러나 이 방법을 사용하여 정적 모듈(즉, 저장소가 생성될 때 선언된 모듈)을 제거할 수는 없습니다. 플러그인Vuex 매장은 각 변이에 대한 후크를 노출하는 플러그인 옵션을 받습니다. Vuex 플러그인은 sotre를 유일한 매개변수로 받아들이는 간단한 방법입니다:
const myPlugin = store => { // 当 store 在被初始化完成时被调用 store.subscribe((mutation, state) => { // mutation 之后被调用 // mutation 的格式为 {type, payload}。 }) }다음과 같이 사용합니다:
const store = new Vuex.Store({ // ... plugins: [myPlugin] })플러그인 내에서 변형 제출 플러그인은 상태를 직접 수정할 수 없습니다. 구성 요소와 마찬가지로 변형에 의해서만 트리거될 수 있습니다. 변이를 제출하면 플러그인을 사용하여 데이터 소스를 스토어에 동기화할 수 있습니다. 예를 들어, websocket 데이터 소스를 저장소에 동기화하기 위해(이는 사용법을 설명하기 위한 예시일 뿐이며 실제로는 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] })상태 스냅샷 생성때때로 플러그인이 상태를 가져오려고 합니다. " 스냅샷" 및 상태는 변경 전후에 변경됩니다. 이러한 기능을 구현하려면 상태 개체의 전체 복사본이 필요합니다.
const myPluginWithSnapshot = store => { let prevState = _.cloneDeep(store.state) store.subscribe((mutation, state) => { let nextState = _.cloneDeep(state) // 对比 prevState 和 nextState... // 保存状态,用于下一次 mutation prevState = nextState }) }** 상태 스냅샷을 생성하는 플러그인은 개발 단계에서 Webpack 또는 Browserify를 사용하여 빌드 도구에서 처리하도록 하세요.
const store = new Vuex.Store({ // ... plugins: process.env.NODE_ENV !== 'production' ? [myPluginWithSnapshot] : [] })플러그인은 기본적으로 활성화됩니다. . 프로덕션으로 배송하려면 Webpack의 DefinePlugin 또는 Browserify의 enify를 사용하여 process.env.NODE_ENV !== 'production'을 false로 변환해야 합니다. 내장 로거 플러그인
如果你正在使用 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 } })
日志插件还可以直接通过 3f1c4e4b6b16bbbd69b2ee476dc4f83a 标签, 然后它会提供全局方法 createVuexLogger 。
要注意,logger 插件会生成状态快照,所以仅在开发环境使用。
严格模式
要启用严格模式,只需在创建 Vuex store 的时候简单地传入 strict: true。
const store = new Vuex.Store({ // ... strict: true })
在严格模式下,只要 Vuex 状态在 mutation 方法外被修改就会抛出错误。这确保了所有状态修改都会明确的被调试工具跟踪。
开发阶段 vs. 发布阶段
不要在发布阶段开启严格模式! 严格模式会对状态树进行深度监测来检测不合适的修改 —— 确保在发布阶段关闭它避免性能损耗。
跟处理插件的情况类似,我们可以让构建工具来处理:
const store = new Vuex.Store({ // ... strict: process.env.NODE_ENV !== 'production' })