-
Vuex 핵심 컨셉(5) - 모듈(module)Vue/Vuex 2021. 7. 2. 11:35
- 단일 상태 트리를 사용하기 때문에 어플리케이션의 하나의 큰 객체 안에 포함
- 규모가 커짐에 따라 저장소는 매우 비대해질 수 있다.
- 이를 위해 Vuex는 Store를 모듈로 나눌 수 있다.
- 각 모듈은 자체 상태, 변이, 액션, getters 및 중첩된 모듈을 포함할 수 있다.
const moduleA = { state: () => ({ ... }), mutations: { ... }, actions: { ... }, getters: { ... } } const moduleB = { state: () => ({ ... }), mutations: { ... }, actions: { ... } } const store = createStore({ modules: { a: moduleA, b: moduleB } }) store.state.a // -> `moduleA`'s state store.state.b // -> `moduleB`'s state
- 모듈 로컬 상태
- 모듈의 변이 및 getters의 첫번째 인자는 모듈의 지역 상태(state)를 받는다.
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: { incrementIfOddOnRootSum ({ state, commit, rootState }) { if ((state.count + rootState.count) % 2 === 1) { commit('increment') } } } }
- 모듈의 getters에서는 세번째 인수로 루트 상태를 받는다.
const moduleA = { // ... getters: { sumWithRootCount (state, getters, rootState) { return state.count + rootState.count } } }
- 네임 스페이스
- 기본적으로 모듈 내의 액션,변이 및 getters는 여전히 전역 네임 스페이스에 등록된다.
여러 모듈이 동일한 변이/액션 유형에 반응 할 수 있다. - 모듈이 독립적이거나 재사용되기를 원한다면 namespaced: true 설정
해당 모듈의 모든 getter, 액션/변이는 자동으로 등록된 모듈의 경로를 기반으로 네임스페이스 지정됨 - 네임 스페이스의 getter와 액션은 지역화된 getters, dispatch, commit을 받는다.
즉, 동일한 모듈 안에서 접두어 없이 모듈을 사용할 수 있다. - 네임 스페이스 옵션 값을 바꾸어도 모듈 내부의 코드에는 영향을 미치지 않는다.
const store = createStore({ modules: { account: { namespaced: true, // module assets state: () => ({ ... }), // module state is already nested and not affected by namespace option getters: { isAdmin () { ... } // -> getters['account/isAdmin'] }, actions: { login () { ... } // -> dispatch('account/login') }, mutations: { login () { ... } // -> commit('account/login') }, // nested modules modules: { // inherits the namespace from parent module myPage: { state: () => ({ ... }), getters: { profile () { ... } // -> getters['account/profile'] } }, // further nest the namespace posts: { namespaced: true, state: () => ({ ... }), getters: { popular () { ... } // -> getters['account/posts/popular'] } } } } } })
- 네임 스페이스 모듈 내부에서 전역 접근
- 전역 상태나 getter를 사용하고자 한다면, rootState와 rootGetters가 getter 함수의 3번째와 4번째 인자로 전달되고, action 함수에 전달된 context 객체의 속성으로도 노출된다.
- 전역 스페이스의 액션을 dispatch하거나 변이를 커밋하려면 dispatch와 commit에 3번째 인자로 { root: true }를 전달하면 된다.
modules: { foo: { namespaced: true, getters: { // `getters` is localized to this module's getters // you can use rootGetters via 4th argument of getters someGetter (state, getters, rootState, rootGetters) { getters.someOtherGetter // -> 'foo/someOtherGetter' rootGetters.someOtherGetter // -> 'someOtherGetter' rootGetters['bar/someOtherGetter'] // -> 'bar/someOtherGetter' }, someOtherGetter: state => { ... } }, actions: { // dispatch and commit are also localized for this module // they will accept `root` option for the root dispatch/commit someAction ({ dispatch, commit, getters, rootGetters }) { getters.someGetter // -> 'foo/someGetter' rootGetters.someGetter // -> 'someGetter' rootGetters['bar/someGetter'] // -> 'bar/someGetter' dispatch('someOtherAction') // -> 'foo/someOtherAction' dispatch('someOtherAction', null, { root: true }) // -> 'someOtherAction' commit('someMutation') // -> 'foo/someMutation' commit('someMutation', null, { root: true }) // -> 'someMutation' }, someOtherAction (ctx, payload) { ... } } } }
- 네임 스페이스 모듈에서 전역 액션 등록
- 네임 스페이스 모듈에서 전역 액션을 등록하려면, root: true를 표시하고 handler 함수에 액션을 정의
{ actions: { someOtherAction ({dispatch}) { dispatch('someAction') } }, modules: { foo: { namespaced: true, actions: { someAction: { root: true, handler (namespacedContext, payload) { ... } // -> 'someAction' } } } } }
- 동적 모듈 등록
- store.registerModule 메서드로 Store가 생성된 후에 모듈을 등록 할 수 있다.
import { createStore } from 'vuex' const store = createStore({ /* options */ }) // register a module `myModule` store.registerModule('myModule', { // ... }) // register a nested module `nested/myModule` store.registerModule(['nested', 'myModule'], { // ... })
- 모듈의 상태는 store.state.myModule 와 store.state.nested.myModule 로 노출 된다.
- 동적 모듈 등록을 사용하면 다른 Vue 플러그인도 에플리케이션의 Store에 모듈을 연결하여 상태 관리에 Vuex를 활용할 수 있다.
- vuex-router-sync 라이브러리는 동적으로 연결된 모듈에서 에플리케이션의 라우트 상태를 관리하여 vue-router와 vuex를 통합한다.
- vuex-router-sync 라이브러리는 동적으로 연결된 모듈에서 에플리케이션의 라우트 상태를 관리하여 vue-router와 vuex를 통합한다.
- store.unregisterModule(moduleName)을 사용하여 동적으로 등록 된 모듈을 제거할 수 있다.
단, 정적 모듈(저장소 생성시 선언 됨)은 제거할 수 없다. - SSR 앱에서 상태를 유지하는 것처럼 새 모듈을 등록할 때 preserveState 옵션을 사용하여 이전 상태를 유지할 수 있다.
- store.registerModule('a', module, { preserveState: true })
- 모듈 재사용
- 한 모듈에서 여러 인스턴스를 생성해야 하는 경우 발생
- 동일 모듈을 사용하는 여러 저장소 생성
- SSR에서 싱글톤 상태 피하기에서 runInNewContext 옵션이 false나 once일 때
- SSR에서 싱글톤 상태 피하기에서 runInNewContext 옵션이 false나 once일 때
- 동일 모듈을 동일 저장소에 여러번 등록
- 동일 모듈을 사용하는 여러 저장소 생성
- 일반 객체를 사용하여 모듈의 상태를 선언하면 상태 객체가 참조에 의해 공유되고 변이될 때 교차 저장소/모듈의 상태 오염을 일으킨다.
- 함수를 사용하여 모듈 상태를 선언
const MyReusableModule = { state: () => ({ foo: 'bar' }), // 변이, 액션, getters... }
[ 참고자료 ]
https://next.vuex.vuejs.org/guide/modules.html
'Vue > Vuex' 카테고리의 다른 글
Vuex 핵심 컨셉(4) - 액션(actions) (0) 2021.07.01 Vuex 핵심 컨셉(3) - 변이(mutations) (0) 2021.07.01 Vuex 핵심 컨셉(2) - Getters (0) 2021.07.01 Vuex 핵심 컨셉(1) - 상태 (0) 2021.07.01 Vuex 시작하기(3) - Store (0) 2021.06.30