본문 바로가기

Development Experience/Web

Vue 독립적인 Component 간의 데이터 통신 (feat. vuex store)

Vue Composition API를 사용하면서 store 데이터를 watch 하는 방법이 손에 익지 않아 기록으로 남겨본다..

 

우선..

내가 구현하고 싶던 기능은 사용자가 웹사이트의 메뉴를 변경할 때 메뉴목록의 하이라이트 지점도 바뀌게 하는 것이었다.

 

이를 위해선 사용자와 인터랙션하는 Component와

메뉴목록을 관리하는 Component 간의 데이터 전달이 필요했다.

 

Vue에서 상태 관리 등 전역으로 다루어야 할 데이터는 vuex의 store 기능을 사용하기에

store의 데이터를 조작하여 Component들 간의 데이터 전달을 하고자 하였다.

 

 

 

작업은 다음의 3 단계로 진행하였다.

 

 

1. Store에 변수 생성

// @/module/common.js

import { createNamespacedHelpers } from "vuex";
export const { mapState, mapMutations, mapActions } =
  createNamespacedHelpers("common");
  
export default {
  namespaced: true,
  state: () => ({
    CUR_MENU: "first-menu",
  }),
  getters: {
    curMenu(state) {
      return state.CUR_MENU;
    },
  },
  mutations: {
    CHANGE_MENU(state, nextMenu) {
      state.CUR_MENU = nextMenu;
    },
  },
};

 

진행중인 프로젝트는 store 변수들을 용도에 따라 여러 파일로 분리하여 관리하고 있다.

메뉴 관련 데이터는 모든 Component에서 공용으로 사용되기 때문에 "@/module/common.js" 파일에 위치한다.

 

여기서 namespace 개념을 사용하는 데, 이것의 중요성을 알지 못해서 초반에 삽질을 좀 하게 되었다...

자세한 건 2, 3번 항목에서 더 다루도록 하자.

 

무튼,

현재 선택된 메뉴를 표시하는 CUR_MENU 변수를 store의 state로 선언하였다.

메뉴를 변경하고자 할 경우 mutations의 CHANGE_MENU()를 호출한다.

메뉴가 변경되었음을 감지하고자 할 경우 getters의 curMenu()를 참조한다.

 

 

2. Store 변수 변경

사용자가 특정 url로 바로 접속하였을 때 그 위치는 첫번째 메뉴가 아닐 수 있다.

이럴 경우 접속한 메뉴에 맞춰 메뉴목록을 업데이트 시켜주어야 했다.

사용자는 두번째 메뉴 화면을 보고 있는데 메뉴목록은 첫번째 메뉴가 선택(하이라이트)되어 있으면 이상하니까.

 

그래서 사용자가 특정 메뉴에 바로 접속하면 onMounted() 함수에서 store의 CUR_MENU 상태를 변경해주어야 한다.

state의 상태 변경은 mutations을 통해 할 수 있으므로 CUR_MENU state를 변경하기 위해 CHANGE_MENU() mutationsonMounted() 훅에서 사용하였다.

 

// 두번째 메뉴 호출 시 onMounted()를 통해 선택된 메뉴가 변경됨을 store에 알림

<script setup>
import { useStore } from "vuex"

const store = useStore()

onMounted(() => {
// commit할 때 namespace (여기선 common) 꼭 붙여줘야 한다 !! 안 그러면 나처럼 몇 시간동안 삽질함..
    store.commit('common/CHANGE_MENU', 'second-menu') 
})

</script>

 

여기서 중요한건 store.commit()을 호출하여 mutaitons을 사용할 때 namespace를 꼭 붙여서 호출해야 한다는 사실이다.

namespace를 붙이지 않으면 Vue가 바보가 된다. 아무리 commit() 해봐도 우리가 원하는 CHANGE_MENU()는 호출되지 않는다..

 

 

3. 변경된 Store 변수를 참조하여 Vue Component 상태 업데이트

자, store의 메뉴 상태가 잘 변경되었다면 이를 감지하여 메뉴목록의 상태도 잘 변경되어야 한다.

상태 변화를 감지하고자 Vue의 computed() 기능을 사용하였다. 바로 살펴보자.

 

<ul>
	<li>
		<a>
			<v-icon class="menu-icon-btn"
				:class="curMenu == 'first-menu' ? 'highlighted' : ''" />
             <v-icon class="menu-icon-btn"
				:class="curMenu == 'second-menu' ? 'highlighted' : ''" />
             <v-icon class="menu-icon-btn"
				:class="curMenu == 'third-menu' ? 'highlighted' : ''" />
		</a>     
	</li>
</ul>

<script setup>
import { computed } from 'vue'
import { useStore } from "vuex"

const store = useStore()

// store의 getters를 호출할 때에도 namespace를 붙여주자!!
var curMenu = computed(() => store.getters["common/curMenu"])
</script>

<style lang="scss" scoped>
.menu-icon-btn {
  background: black;
  color: white;
}

.highlighted {
  background: white;
  color: black;
}
</style>

 

store의 상태 변화를 얻기 위해선 getters를 사용해야 하므로,

curMenu getters를 호출하여 CUR_MENU state 값을 불러왔다.

 

그리고 CUR_MENU state가 변경될 때마다 해당 값에 맞게

하이라이트되는 메뉴가 바뀌어야 하므로 Vue의 computed() 기능을 사용하였다.

 

그리고 2번에서와 같이 store의 commit()을 할 때에는 namespace를 꼭!꼭! 붙여주자!!

반응형