관리 메뉴

KorSA

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

Development Experience/Web

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

Praiv. 2022. 9. 21. 15:27
320x100

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를 꼭!꼭! 붙여주자!!

728x90
728x90
Comments