본문 바로가기
Programming/Vue.js

Vue.js에서 Vuex 사용하기(2) [state, actions, mutations]

by 주리니e 2023. 1. 3.
728x90

Vue.js에서 Vuex 사용하기(2) [state, actions, mutations]

 

 

 

지난 시간에는 간단하게 Vuex를 설치하고 세팅, 선언된 값의 간단한 사용방법에 대해 알아보았다. 이번 시간에는 서버에서 데이터를 가져오는 방법(actions)과 수정 및 가공하는 방법(mutations)과 추가적으로 사용할 수 있는 방법에 대해서 알아보자. 또한 mapState와 mapMutations을 활용하여 간단하게 축약하여 사용해보자.

 

  • Axios 설치

vuex의 actions에서 ajax통신을 할 예정이므로 axios를 설치하자.

> npm install axios

 

 

  • 상태 (state)

상태(state)는 애플리케이션에서 관리되어야 할 구성요소이며 데이터이다. 이 값은 여러 컴포넌트에 의해 사용될 수 있다. 또한 컴포넌트에 의해 직접적으로 수정할 수 있으나 권고되지 않는 방식이다. 수정을 하려면 변이(mutation)을 거쳐서 수정해야 한다. 컴포넌트에 의해 직접 수정이 된다면 어느 컴포넌트에서 이 값이 수정되었는지 추적이 힘들기 때문이므로 반드시 mutations을 거쳐 수정하도록 하자. 

state() {
  return {
    name: "jiurinie",
    age: 20,
    email: "jiurinie@gmail.com",
    data: {},
  };
},
# HTML 
<h4>안녕 {{ $store.state.name }} 나이는 {{ $store.state.age }}</h4>

# script
console.log(this.$store.state.name);

 

 

  • 변이 (mutations)

변이(mutations)은 state를 수정할 수 있는 기능을 제공하는 목적으로 만든다. 일반적인 메소드와 같으며 컴포넌트에서 호출 시 $store.commit('이름') 을 사용하여 호출한다.

mutations: {
  changeName(state) {
    state.name = "player1";
  }, 
  addAge(state, data) {
    state.age += data;
  },
  showData(state, data) {
    state.data = data;
  },
},
# HTML
<button @click="$store.commit('changeName')">
    store.js에게 이름 변경 부탁하기 버튼
</button>

# script
this.$store.commit('changeName');

 

 

  • 액션(actions)

액션은 ajax를 호출하거나 속도가 오래걸리는 경우에 사용한다. 변이(mutations)에서 ajax 통신을 해도 되지만 순차적으로 상태(state)를 변경하고 싶은 2개의 함수가 있는 경우에는 순차적 실행을 보장할 수 없는 경우가 생기기 때문이다. 액션 후 상태의 변경은 반드시 변이(mutations)에서 해야 한다. 액션에서 커밋을 쓸때에는 context라는 파라미터를 관습적으로 사용한다.

actions: {
  getData(context) {
    axios.get('https://jsonplaceholder.typicode.com/todos/0').then((result) => {
      context.commit("showData", result.data);
    });
  },
},
# HTML
<p>{{ $store.state.data }}</p>
<button @click="$store.dispatch('getData')">데이터 가져오기 버튼</button>

# script
this.$store.dispatch('getData');

 

 

  • mapState, mapMutations

vuex의 mapState와 mapMutations를 이용하면 간단하게 store에 선언된 state나 mutations를 사용할 수 있다. 복잡하게 $store.state.name 등 길고 복잡하게 사용할 필요없이 컴포넌트에 선언된 데이터나 메소드처럼 사용하면 된다. 

<template>
  <div>
    <h4>'mapState를 활용한 데이터 가져오기' :  안녕 {{ name }} 나이는 {{ age }}</h4>
    <button @click="addAge(10)">
      mapMutations를 활용하여 store.js에게 나이 변경 부탁하기 버튼
    </button>
  </div>
</template>

<script>
import { mapState, mapMutations } from "vuex";

export default {
  name: "App",
  components: {},
  computed: {
    name() {
      return this.$store.state.name;
    },
    ...mapState(["age", "email"]),
  },
  methods: {
    ...mapMutations(["addAge"]),
  }
};

 

 

  • App.vue
<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <h4>안녕 {{ $store.state.name }} 나이는 {{ $store.state.age }}</h4>
  <h4>'mapState를 활용한 데이터 가져오기' :  안녕 {{ name }} 나이는 {{ age }}</h4>
  <button @click="$store.commit('changeName')">
    store.js에게 이름 변경 부탁하기 버튼
  </button>
  <button @click="addAge(10)">
    mapMutations를 활용하여 store.js에게 나이 변경 부탁하기 버튼
  </button>
   <p>{{ $store.state.data }}</p>
  <button @click="$store.dispatch('getData')">데이터 가져오기 버튼</button>
</template>

<script>
import { mapState, mapMutations } from "vuex";

export default {
  name: "App",
  components: {},
  computed: {
    name() {
      return this.$store.state.name;
    },
    ...mapState(["age", "email"]),
  },
  methods: {
    ...mapMutations(["addAge"]),
  }
};
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

 

 

  • store.js
import { createStore } from "vuex";
import axios from "axios";

const store = createStore({
  state() {
    return {
      name: "jiurinie",
      age: 20,
      email: "jiurinie@gmail.com",
      data: {},
    };
  },
  mutations: {
    changeName(state) {
      state.name = "player1";
    },
    addAge(state, data) {
      state.age += data;
    },
    showData(state, data) {
      state.data = data;
    },
  },
  actions: {
    getData(context) {
      axios.get('https://jsonplaceholder.typicode.com/todos/0').then((result) => {
        context.commit("showData", result.data);
      });
    },
  },
});

export default store;

728x90

댓글