개발 도구 (Development Tools)/Vue

Vue - vuex 사용하는 방법

BiCute 2022. 10. 3. 08:00
반응형

 

1. vuex를 사용하는 이유

  프로젝트가 커질수록 다양한 컴포넌트에서 서로 연관있는 데이터를 주고받게 되는데, vue는 부모에게서 자식에게로 props로만 데이터를 전송하게 된다. 이러한 방식은 컴포넌트끼리의 관계가 복잡해질수록 데이터를 공유하기 매우 힘들어진다. 

  vuex는 중앙 집중식 저장소 역할을 하며, 여러 컴포넌트에서 쓸 데이터를 보관하고, 언제든 데이터를 바로 가져다 쓸 수 있게 도와준다.

 

마냥 좋아보이는데 그럼 왜 처음부터 vuex를 쓰지 props를 쓰는것인가?

  vuex를 사용하게되면 데이터에 대한 접근은 쉬워지지만 우선 코드가 길고 복잡해진다.

  그렇기에 개인 프로젝트정도의 작업이나 특정 컴포넌트에서만 사용되는 정도는 vuex없이 사용하는편이 더 간편해진다.

  하지만 실제로 작업을 하게되면 vuex는 필수적으로 사용하게 되니 사용방법을 알아놓는것이 좋다. 

 

 

 

2. vuex 설치와 세팅

 

npm 설치

npm install vuex@next

 

 

src 폴더 안에 store.js 생성 후 다음과 같은 형태로 작성한다.

(아래에서 하나하나 다루겠지만 state() 는 기존에 data 작성하는것과 동일하며, mutations 는 methods와 같다고 생각하면 되니 어렵게 생각하지 않아도 된다) 

(store.js)

import { createStore } from 'vuex'

const store = createStore({
  state () {
    return {

    }
  },
  mutations: {

  }
})

export default store;

main.js에 store를 추가해준다.

(main.js)

import { createApp } from 'vue'
import App from './App.vue'

let app = createApp(App);
import store from './store.js'  //<-- 추가

app.use(store).mount('#app')   //<-- app.use(store) 추가

 

 

 

3. store 기본사용방법

 

(1) 데이터 등록과 데이터 바인딩

  데이터는 기존에 사용하던 방식과 동일하게 [이름: 데이터값] 형태로 데이터를 생성할 수 있습니다.

  vuex에서는 data가 아닌 state라고 부릅니다.

(store.js)

import { createStore } from 'vuex'

const store = createStore({
    state() {
        return {
            number: 1,  // <--  기존 데이터 입력하는것과 동일하게 state에 지정
            text: 'HELLO'
        }
    },
    mutations: {
        plusNumber(state) {  // <-- 기존 methods 작성하는 방법과 동일하게 작성
            state.number ++
        }
    }
})

export default store;
(App.vue)

<template>
  <div>
    <p> {{ $store.state.number }} </p>
    <button @click="$store.commit('plusNumber')">카운트 증가</button>
  </div>
</template>

store에 있는 데이터에 접근할 때는, [$store.state.데이터이름] 형식으로 작성합니다.

 

 

(2) 데이터(state)를 변경하는 방법.

vuex는 store에 있는 데이터를 컴포넌트에서 직접 변경하지 말라고 합니다.

store의 데이터 값을 변경하고 싶을때는 기존의 부모 요소에게 요청하던 방식($emit)처럼 store에게 수정해달라고 요청을 해야합니다.

수정을 요청하기 위해선 당연히 store.js에 수정 방법을 미리 정의해 놓아야 합니다.

정의할 내용은 기존 methods를 사용하듯 mutations 영역을 만들어 작성하면 됩니다.

위 예제에서는 store.js에 누군가가 plusNumber라고 요청을 하면 number의 숫자를 증가시키겠다고 미리 정의가 되어있습니다.

mutations: {
  changeNumber(state) {  // <-- 데이터에 접근할때는 파라미터로 state를 넣어준 후,
    state.number ++  // <-- state.데이터 로 접근할 수 있다
  }
}

 

store의 mutations에 요청하기 위해선 $store.commit('함수명') 형식으로 사용합니다.

(App.vue)

<template>
  <div>
    <p> {{ $store.state.number }} </p>
    <button @click="$store.commit('plusNumber')">카운트 증가</button>
  </div>
</template>

※ mutation의 함수는 2개의 인자를 가질 수 있는데, 첫번째는 state이며 두번째는 payload(해당 데이터를 담아 보냄)입니다. 

 

patload 사용 예)

mutations: {
  increment (state, n) {
    state.count += n
  }
}
$store.commit('increment', 10)

 

 

 

4. actions

  actions또한 mutations와 비슷합니다만, 

  이곳에는 비동기 작업(axios같은 서버와의 통신이나 setTimeout같이 시간이 걸리는 작업)에 관한것들을 요청하는 곳입니다.

const store = createStore({
  state: {
    number: 0
  },
  mutations: {
    plusNumber (state) {
      state.number++
    }
  },
  actions: {
    increment (context) {
      context.commit('plusNumber')
    }
  }
})

actions는 dispatch로 요청을 합니다.

또한 데이터는 반드시 mutations를 통해 변경해야 하기 때문에 작업 내용중 데이터 변경이 필요하다면

context.commit('mutation함수명') 형식으로 해당 함수를 호출해서 수정을 해야 합니다.

commit 을 하기위해선 첫번째 인자로 context를 받아오며, 2번째 인자로 mutations와 같이 payload를 받을 수 있습니다.

※ context는 state, commit, dispatch, rootstate와 같은 속성이 포함되어 있습니다

$store.dispatch('increment')

 

 

 

 

5. state에 조금더 쉽게 접근할 수 있는 방법 2가지.

 

(1) return 활용

  위 예문에선 state에 접근하기 위해선 다음과 같이 작성했었습니다.

<p> {{ $store.state.number }} </p>

 

매번 이렇게 $store.state.이름 형식으로 적는게 복잡하고 귀찮다면 다음과 같이 computed에 return 값을 줘서 함수 이름만 사용하는것으로 해당 값을 사용할 수 있습니다.

<template>
  <div>
    <p> {{ number }} </p>
    <button @click="$store.commit('plusNumber')">카운트 증가</button>
  </div>
</template>


<script>
export default {
  name: 'App',
  computed: {
    number() {
      return this.$store.state.number
    }
  }
}
</script>

 

 

(2) 컴포넌트 바인딩 헬퍼

  mapState, mapMutations, mapActions, mapGetters라는 바인딩을 도와주는 바인딩 헬퍼 함수들이 있습니다.

  computed에서 헬퍼 함수 앞에 스프레드 오퍼레이터(...)와 함께 작성한 후, () 내부에 적용할 대상을 배열 형식으로 넣어주면 됩니다.

  

<template>
  <div>
    <p> {{ number }} </p>
    <p> {{ text }} </p>
    <button @click="$store.commit('plusNumber')">카운트 증가</button>
  </div>
</template>


<script>
import { mapState } from 'vuex'  // <-- mapState를 import (자동완성 잘해줌)
export default {
  name: 'App',
  computed: {
    ...mapState(['number', 'text'])  // <-- 추가
  }
}
</script>

 

위 예시는 mapState를 예로 들었기에 store에 정의된 state의 이름들이 computed에 들어가 있는 것이며,

mapMutations나 mapActions같은 것들은 methods안에 함수 이름으로 작성해주면 됩니다. (import 잊지 마시고!)

<template>
  <div>
    <p> {{ number }} </p>
    <p> {{ text }} </p>
    <button @click="plusNumber">카운트 증가</button>  //<-- 간편하게 함수명만 사용 가능
  </div>
</template>


<script>
import { mapMutations, mapState } from 'vuex'  // <-- import
export default {
  name: 'App',
  computed: {
    ...mapState(['number', 'text']),
  },
  methods: {
    ...mapMutations(['plusNumber'])  // <-- 추가
  },
}
</script>

 

 

 

반응형