본문 바로가기

웹/TIL

0516 Vuex

Vuex

: Vue.js 어플리케이션에 대한 상태 관리 패턴 + 라이브러리

여기서 상태란, 뷰 인스턴스 내부의 data()를 가리킨다.

 

new Vue({
  // 상태
  data () {
    return {
      count: 0
    }
  },
  // 뷰
  template: `
    <div>{{ count }}</div>
  `,
  // 액션
  methods: {
    increment () {
      this.count++
    }
  }
})

 

Vuex는 어플리케이션 내 모든 컴포넌트들의 중앙 저장소 역할을 하며 예측 가능한 방식(정해진 방식)으로 상태를 변경할 수 있다.

언제, 왜 사용할까?

Vue의 데이터 흐름이 단방향이기 때문에 컴포넌트 간의 상위, 하위 단계가 많아진다면 데이터를 전달하는 부분이 매우 복잡해진다.

Event Bus를 이용해 동위 컴포넌트 간의 data 전달도 가능하지만 데이터의 흐름을 파괴할 수 있기 때문에 거의 쓰지 않는다.

 

기존 방식

 

이때 Vuex의 저장소(store)를 사용하면 computed처럼 값이 변경되었을 때 이를 감지하고 자동으로 컴포넌트들의 값을 변경해준다.

 

Vuex

 

이처럼 Vuex는 공유된 상태를 관리할 때 유용하지만 개념에 대한 이해와 비용이 필요하다.

따라서 컴포넌트가 많은 대규모의 SPA에서 사용하는 것이 좋다.

핵심 컨셉

우선 전체적인 그림을 보자면

1. Vue Component에서 데이터를 바꾸려면 dispatch를 호출해

2. Actions 내부의 method를 실행한다.

3. 백엔드에서 얻어온 데이터는 commit을 통해

4. Mutations가 가진 method를 호출하고

5. state를 변경(mutate)해준다.

 

각 컨셉들을 좀더 자세히 살펴보자.

State

Vuex는 Single State Tree(단일 상태 트리)를 사용한다. 즉, 하나의 store만 사용한다는 뜻이다.

  • Vuex Store에서 컴포넌트에서 사용하는 state(data)를 한 눈에 파악이 가능하다.
  • Mutations에 정의된 method에 의해 변경된다.
  • State가 변경되면 해당 state를 공유하는 모든 컴포넌트의 DOM은 자동으로 렌더링 된다.
  • 각 컴포넌트는 dispatch()를 사용하여 Actions 내부의 method를 호출한다.

Actions

  • BackEnd API와 통신하여 Data Fetching 등의 작업을 수행한다. 보통 비동기 작업을 담당한다.
  • 항상 context가 인자로 넘어온다.
  • 보통 Actions는 소문자로, Mutations는 대문자로 작성한다. (필수 x)
store.js가 가진 모든 요소(속성, method)의 변경 및 호출이 가능하지만, state를 직접 변경하는 것은 권장하지 않는다.

State는 반드시 Mutations가 가진 method를 통해서만 조작한다. 이는 서비스 규모가 커지더라도 state 관리를 올바르게 하기 위함이다.

mapActions

this.$store.dispatch('~~')의 반복을 막기위해 mapActions를 사용할 수 있다.

 

  methods: {
    asyncCount() {
      this.$store.dispatch("asyncAddOne");
    },
  },

 

위의 코드를 아래처럼 바꿀 수 있다.

 

<script>
import { mapActions } from "vuex";
export default {
  name: "SubjectComponent",
  props: ["title"],
  data() {
    return {
      count: 0,
    };
  },
  methods: {
    ...mapActions(["asyncAddOne"]),
    asyncCount() {
      this.asyncAddOne();
    },
  },
};
</script>

Mutations

  • Actions에서 commit() method를 통해 호출된다.
  • Mutations에 비동기적 작업이 있을 경우 state의 변화 시점이 명확하지 않을 수 있기 때문에 동기적 작업만을 한다.
  • 첫 번째 인자로 state가 넘어온다.

mapMutations

mutations를 간단하게 호출하는 방법이다.

원래는 this.$store.commit('method_name') 으로 호출하지만 간단하게 this.method_name() 로 호출할 수 있다.

 

<script>
export default {
  name: "SubjectComponent",
  props: ["title"],
  data() {
    return {
      count: 0,
    };
  },
  methods: {
    addCount: function () {
      this.count += 1;
      this.$store.commit("ADD_ONE");
      // this.$store.state.count++;
    },
    addTenCount: function () {
      this.count += 10;
      this.$store.commit("ADD_COUNT", 10);
    },
    addObjCount: function () {
      let num = Math.round(Math.random() * 100);
      console.log(num);
      this.count += num;
      this.$store.commit("ADD_OBJ_COUNT", { num });
    },
  },
};
</script>

 

위와 같은 코드를 아래처럼 바꿀 수 있다.

 

<script>
import { mapMutations } from "vuex";
export default {
  name: "SubjectComponent",
  props: ["title"],
  data() {
    return {
      count: 0,
    };
  },
  methods: {
    ...mapMutations({
      addMOne: "ADD_ONE",
      addMTenCount: "ADD_TEN_COUNT",
      addMObjCount: "ADD_OBJ_COUNT",
    }),
    addCount: function () {
      this.count += 1;
      // this.$store.commit('addOne');
      this.addMOne();
    },
    addTenCount: function () {
      this.count += 10;
      // this.$store.commit('addCount', 10);
      this.addMTenCount(10);
    },
    addObjCount: function () {
      let num = Math.round(Math.random() * 100);
      this.count += num;
      // this.$store.commit('addObjCount', { num });
      this.addMObjCount({ num });
    },
  },
};
</script>

Getters

Computed와 유사하다.

State를 직접적으로 변경하는 것이 아니라, State를 활용하여 계산을 수행한 뒤 결과값만 넘겨준다.

mapGetters

getters를 조금 더 간단하게 호출하는 방법이다.

원래는 this.$store.getters.method_name 과 같은 형식으로 호출하지만 mapGetters 를 사용해 더 간편하게 getters를 사용할 수 있다.

 

<script>
export default {
  computed: {
    countMsg() {
      return this.$store.getters.countMsg;
    },
  },
};
</script>

 

위와 같은 코드를 아래처럼 변경할 수 있다.

아래는 this.$store.getters.countMsg 를 this.countmsg 라는 이름으로 매핑한 예시이다.

 

<script>
import { mapGetters } from "vuex";

export default {
  computed: {
    ...mapGetters({
      countmsg: "countMsg",
    }),
    // ...mapGetters(["countMsg"]),
  },
};
</script>

' > TIL' 카테고리의 다른 글

티스토리 마크다운 제대로 적용하기  (0) 2023.05.12
0916 Blockchain  (0) 2022.09.16
0512 Vue CLI  (0) 2022.05.12
0510 Vue.js (3)  (0) 2022.05.10
0509 Vue.js (2)  (0) 2022.05.09