티스토리 뷰

Vue.JS

[vuex] Actions

버미노트 2019. 7. 11. 00:40

Action은 Mutation과 비슷하지만, 몇가지 차이점이 있습니다.

  1. state를 변경하지 않고 Mutation의 핸들러 함수를 호출합니다.
  2. 비동기 작업을 수행할 수 있습니다.
const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      context.commit('increment')
    }
  }
})

위의 코드와 같이 action을 등록 할 수 있습니다. action의 핸들러는 context 객체를 전달인자로 받습니다. context 객체는 store의 메소드와 속성들을 가지고 있는 객체입니다. 그래서 context.commit를 호출하여 Mutation의 핸들러를 호출하거나, context.statecontext.getters를 통해 state와 getter에 접근 할 수 있습니다.

actions: {
  increment ({ commit }) {
    commit('increment')
  }
}

코드를 단순화하기 위해서 ES6에 추가된 구조분해할당를 사용할 수 있습니다.

1. Dispatch

action의 핸들러는 store.dispatch 메소드를 사용하여 호출 할 수 있습니다.

store.dispatch('increment')

store.commit('increment')를 직접 호출하지 않는 이유는 비동기에 있습니다. Mutation은 반드시 동기적으로 작성되어야 한다고 이전 포스트([vuex] Mutations 참고)에서 이야기 했습니다.

actions: {
  incrementAsync ({ commit }) {
    setTimeout(() => {
      commit('increment')
    }, 1000)
  }
}

action의 핸들러에서는 위의 코드와 같이 비동기 작업을 수행 할 수 있습니다.

객체 스타일 payload

Mutation과 동일하게 객체 스타일 payload 기능을 제공합니다.

// 페이로드와 함께 디스패치
store.dispatch('incrementAsync', {
  amount: 10
})

// 객체와 함께 디스패치
store.dispatch({
  type: 'incrementAsync',
  amount: 10
})

비동기 Back-End API 호출

action의 실용적인 사용법은 비동기 Back-End API를 호출 하는 것입니다.

actions: {
  checkout ({ commit, state }, products) {
    // 장바구니에 현재있는 항목을 저장하십시오.
    const savedCartItems = [...state.cart.added]

    // 결제 요청을 보낸 후 장바구니를 비웁니다.
    commit(types.CHECKOUT_REQUEST)

    // 상점 API는 성공 콜백 및 실패 콜백을 받습니다.
    shop.buyProducts(
      products,
      // 요청 성공 핸들러
      () => commit(types.CHECKOUT_SUCCESS),
      // 요청 실패 핸들러
      () => commit(types.CHECKOUT_FAILURE, savedCartItems)
    )
  }
}

위의 예제 코드와 같이 action의 효율적인 사용방법은 Back-End 비동기 API를 호출하고, 응답을 받은 후 Mutation의 핸들러를 호출하여 state를 변경하는 것입니다.

2. mapActions

this.$store.dispatch('xxx')를 사용하여 컴포넌트에서 action의 핸들러 함수를 호출할 수 있습니다. 또 다른 방법으로 mapActions를 사용할 수 있습니다.

import { mapActions } from 'vuex'

export default {
  // ...
  methods: {
    ...mapActions([
      'increment' // this.increment()을 this.$store.dispatch('increment')에 매핑
    ]),
    ...mapActions({
      add: 'increment' // this.add()을 this.$store.dispatch('increment')에 매핑
    })
  }
}

3. Action 사용하기

이제는 Action을 어떻게 사용할 수 있는지 이야기 해 보도록 하겠습니다. action은 종종 비동기적으로 작성됩니다. action의 비동기처리는 어떻게 할 수 있는지 이야기 할 것입니다.
store.dispatch의 반환 값은 Promise입니다. store.dispatch로 호출한 action의 핸들러 함수의 Promise 반환 값을 처리 할 수 있습니다.

actions: {
  actionA ({ commit }) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        commit('someMutation')
        resolve()
      }, 1000)
    })
  }
}

action의 핸들러 함수가 위의 코드와 같이 작성되었다면,

store.dispatch('actionA').then(() => {
  // ...
})

위의 코드와 같이 Promise의 비동기처리를 사용할 수 있습니다.

// getData() 및 getOtherData()가 Promise를 반환한다고 가정합니다.
actions: {
  async actionA ({ commit }) {
    commit('gotData', await getData())
  },
  async actionB ({ dispatch, commit }) {
    await dispatch('actionA') // actionA가 끝나기를 기다립니다.
    commit('gotOtherData', await getOtherData())
  }
}

Promise를 사용할 수 있다면, 당연히 ES8에 추가된 async/await 문법([자바스크립트] ES8(ECMA Script 8) - async, await 참고)도 사용 할 수 있습니다.

actions: {
  // ...
  actionB ({ dispatch, commit }) {
    return dispatch('actionA').then(() => {
      commit('someOtherMutation')
    })
  }
}

또, 위의 코드와 같이 action의 핸들러 안에서 다른 action의 핸들러를 호출 할 수도 있습니다.

참고

'Vue.JS' 카테고리의 다른 글

[vuex] Plugins  (0) 2019.07.16
[vuex] Modules  (0) 2019.07.16
[vuex] Actions  (0) 2019.07.11
[vuex] Mutations  (0) 2019.07.10
[vuex] Getters  (0) 2019.07.02
[vuex] State  (0) 2019.06.28
댓글
댓글쓰기 폼