Notice
Recent Posts
Recent Comments
관리 메뉴

즐겁게, 코드

Vuex의 namespaced module 활용하기 본문

🎨 프론트엔드/Vue.js

Vuex의 namespaced module 활용하기

Chamming2 2022. 4. 4. 20:47

어플리케이션의 규모가 커지면 인증 정보, 장바구니 목록, 어플리케이션 설정 등 전역으로 관리해야 할 요소의 성격이 완전히 다른 경우가 종종 생기는데요, Reactredux를 사용할 때는 이처럼 둘 이상의 관심사가 있을 때 여러 스토어를 만들고 combineReducers 함수를 사용해 스토어를 하나로 묶어 사용했습니다.

 

오늘은 VueVuex를 사용해 스토어를 구성할 때, 관심사별로 유사한 상태를 묶어 관리할 수 있도록 해주는 네임스페이스(namespace) 에 대해 소개해보도록 하겠습니다. 🙂

네임스페이스의 등장 배경

어플리케이션이 하나의 스토어를 가질 때는 store 라는 폴더 안에 index.js, mutations.js, actions.js, getters.js 라는 이름을 가진 각 파일(vuex 모듈)을 통해 전역 상태를 관리할 수 있습니다.

store
├─ index.js # 전역 상태를 관리합니다.
├─ mutations.js # 전역 상태를 동기적으로 변경하는 함수를 관리합니다.
├─ actions.js # 전역 상태를 비동기적으로 변경하는 함수를 관리합니다.
├─ getters.js # 전역 상태로부터 파생되는 값을 관리합니다.

하지만, 한 index.js 에 관심사가 다른 여러 상태가 있으면 자연스레 스토어가 복잡해지게 됩니다.

// 각각 관심사가 완전히 다른 인증(Auth), 할일 목록(Todo)의 상태입니다.

export const state = () => ({
  isLoggedIn: null,
  activeUser: null,
  todoList: null,
  selectedTodoList: null;
})

이렇게 다른 관심사를 갖는 상태를 보다 명확한 단위로 구분하기 위해 Vuex에서는 스토어를 namespace 단위로 나누어 각 스토어의 관심사를 분리할 수 있습니다.

네임스페이스 모듈 작성하기

그럼 namespace 를 적용하면 파일 구조가 어떻게 개선될 수 있는지 확인해 보겠습니다.

아래 폴더 구조에서는 인증 정보를 관리하는 Auth 라는 폴더와, 할일 목록을 관리하는 Todo 라는 폴더를 생성한 모습입니다.

✅ 폴더의 이름이 곧 Vuex 네임스페이스가 됩니다.

store
├─ Auth
│  ├─ actions.js
│  ├─ mutations.js
│  ├─ index.js
│
├─ Todo
   ├─ actions.js
   ├─ mutations.js
   ├─ index.js

이제 두 스토어의 폴더가 물리적으로 분리되었으니 각 스토어의 관심사 역시 자연스럽게 분리됩니다.

보다시피 이전에는 한 state 안에 모든 전역 상태를 보관했다면, 이제는 AuthTodo 의 상태를 명확히 분리할 수 있게 된 모습입니다.

// store/Auth/index.js
export const state = () => ({
  isLoggedIn: null,
  activeUser: null,
});
// store/Todo/index.js
export const state = () => ({
  todoList: null,
    selectedTodoList: null;
})

마찬가지로, mutations.jsactions.js 역시 동일한 방법으로 분리할 수 있게 됩니다.

// store/Todo/mutations.js
// mutations.js 에는 뮤테이션 함수를 내보냄과 동시에 정의합니다.

export const mutateTodoList = (state, updatedTodoList) => {
  state.todoList = updatedTodoList;
};

🚨 반드시 주의하세요!

namespace 문법을 사용할 때는 반드시 각 모듈을 export default 가 아닌, export 로 내보내야만 합니다.

만약 export default 문으로 상태 또는 뮤테이션 등을 내보낼 시, Vuex는 이를 올바른 모듈로 인식하지 못하여 Vuex 상태에 제대로 읽고 쓸 수 없습니다.

 

(이는 Nuxt 2.15.8 버전에서 발생하는 이슈로, 정확히 Nuxt의 이슈인지 Vuex의 이슈인지는 파악하지 못했습니다 😢)

네임스페이스 모듈 사용하기

이제 컴포넌트 내부에서 네임스페이스 모듈을 사용하는 방법을 알아보겠습니다.

index.js, mutations.js, actions.js, getters.js 모듈을 불러올 때는 map- 으로 시작하는 헬퍼 함수를 사용할 수 있는데요, 한번 아래 코드를 예시로 살펴보겠습니다.

computed: {
  // mapState 함수는 computed 내부에서 스프레드 연산자와 함께 사용합니다.
  // Ex- ...mapState('네임스페이스 이름', ['사용할 상태명']);
  ...mapState('Todo', ['todoList']);

  // 둘 이상의 상태도 불러올 수 있습니다.
  ...mapState('Auth', ['isLoggedIn', 'activeUser']);

    // mapGetters의 사용 방법 역시 동일합니다.
}

methods: {
    // mapMutations 함수는 methods 내부에서 스프레드 연산자와 함께 사용합니다.
  // Ex- ...mapMutations('네임스페이스 이름', ['사용할 뮤테이션 명']);
  ...mapMutations('Todo', ['mutateTodoList']);

  // 둘 이상의 뮤테이션 함수도 불러올 수 있습니다.
  ...mapMutations('Auth', ['signIn', 'signOut']);

  // mapActions의 사용 방법 역시 동일합니다.
}

이제 map- 헬퍼를 통해 어떤 네임스페이스의 상태를 가져오거나 조작할지 보다 명확하게 나타낼 수 있게 되었습니다.

간단한 실제 적용 사례

제가 작업하고 있는 프로젝트 중, mapStatemapMutations 를 불러와 사용하는 유스케이스입니다.

<template>
  <Home />
</template>

<script>
  import getLocalANSData from "@/apis/ANSData/getLocalANSData";
  import { mapMutations, mapState } from "vuex";

  export default {
    name: "MainPage",
    components: {
      Home: () => import("@/components/pages/home"),
    },
    async mounted() {
      const { data } = await getLocalANSData();
      this.initData(data);
    },
      computed: {
          ...mapState("Auth", ["activeUser"]);
      },
    methods: {
      ...mapMutations("ansData", ["mutateANSData"]),
      initData(data) {
        this.mutateANSData(data);
      },
    },
  };
</script>

오늘 다룬 네임스페이스 문법이 코드 개선에 도움이 되시길 바라며, 다음에는 더 나은 글로 찾아뵙도록 하겠습니다. 🙂

반응형
Comments
소소한 팁 : 광고를 눌러주시면, 제가 뮤지컬을 마음껏 보러다닐 수 있어요!
와!! 바로 눌러야겠네요! 😆