본문 바로가기
Front-end/Vue3

37. Vue - vuex helper

by devraphy 2021. 6. 21.

1. Vuex Helper

이전 포스팅에서 Store 개념을 사용하기 위해 Vuex를 설치하고 사용법을 익혀보았다. 

이번 포스팅에서는 Vuex를 사용하여 반복되는 코드를 줄이고 코드의 효율성 및 재활용을 높이는 방법을 알아보자. 

 

a. mapState

https://next.vuex.vuejs.org/guide/state.html#the-mapstate-helper

 

State | Vuex

State Single State Tree Vuex uses a single state tree - that is, this single object contains all your application level state and serves as the "single source of truth." This also means usually you will have only one store for each application. A single st

next.vuex.vuejs.org

 

computed: mapState([
  // map this.count to store.state.count
  'count'
])

mapState() 라는 함수 내부에 배열([])을 선언한 후, 사용할 state의 이름만을 위의 예시 코드처럼 명시해주면 되는 것이다.

mapState()를 사용하면 state를 가져오기 위해 작성하는 코드를 간소화 할 수 있다.  

 

b. 여러가지 Helper 

단순히 computed에서 state를 간단한 방식으로 불러오기 위해 Helper를 사용하는 것이 아니라 Getters, Mutations, Actions, Modules 모두 각각의 Helper를 Vuex에서 제공하고 있다.

 

위에 적어놓은 공식문서 링크를 통해 쉽게 확인 할 수 있으니, 참고하기를 바란다.  


2. 적용하기 

<script>
import Loader from '~/components/Loader'

export default {
  components: {
    Loader
  },
  data() {
    return {
      imageLoading: true
    }
  },
  computed: {
    image() {
      return this.$store.state.about.image
    },
    name() {
      return this.$store.state.about.name
    },
    email() {
      return this.$store.state.about.email
    },
    phone() {
      return this.$store.state.about.phone
    },
    blog() {
      return this.$store.state.about.blog
    }
  },
  mounted() { // 라이프 사이클에서는 비동기 처리가 안됨
    this.init()
  },
  methods: {
    async init() {
      await this.$loadImage(this.image)
      this.imageLoading = false
    }
  },
}
</script>

위의 코드에서 computed 속성 부분에 반복되는 코드를 예제로 사용할 것이다.

mapState() 함수를 어떻게 적용하여 코드를 간소화 할 수 있는지 알아보자.

 

 

<script>
import Loader from '~/components/Loader'
import {mapState} from 'vuex'

export default {
  components: {
    Loader
  },
  data() {
    return {
      imageLoading: true
    }
  },
  computed: {
    ...mapState('about', [ // state의 about이라는 모듈 안에 있는 데이터를 가져온다는 의미
      // 전개연산자(...)를 사용하는 이유는 
      // mapState()에서 반환된 결과가 computed 객체데이터 내부에서 등록 되도록 하기 위함. 
      'image',
      'name',
      'email',
      'phone',
      'blog'
    ]
    ),
  },
  mounted() { // 라이프 사이클에서는 비동기 처리가 안됨
    this.init()
  },
  methods: {
    async init() {
      await this.$loadImage(this.image)
      this.imageLoading = false
    }
  },
}
</script>

위의 코드에서 가장 중요한 부분은 script 태그 바로 아래부분에 import를 사용하여 mapState를 가져오는 부분이다. 

이 부분을 사용해야 mapState를 사용할 수 있다. 

 

개발환경에 따라서 다르지만, 굳이 import를 작성하지 않아도 mapState() 함수를 사용하면 자동으로 입력될 수도 있으니 참고하자. 

 

만약, 전개 연산자를 사용하지 않는다면, 다음과 같이 코드를 작성할 수 있다. 

아래의 사진과 같은 mapState의 사용방식은 공식문서에 나와있는 방식이다.

클릭하면 확대됩니다.

 

만약 mapState가 이외에도 다른 계산된 데이터를 computed에서 사용한다면, 위의 코드처럼 전개 연산자를 사용하여 다른 computed를 같이 사용할 수 있는 환경을 만들어 줄 수 있음을 참고하자. 즉, 전개연산자를 사용하여 mapState()를 사용하는 것을 권장한다. 

 

클릭하면 확대됩니다.


3. this를 활용한 데이터 접근 

만약 methods 속성에서 computed에 정의된 mapState()에 접근하고 싶다면 this를 활용하면 된다. 

 

이것이 가능한 이유는 mapState()를 사용하였으나 해당 데이터 또는 state 들은 computed에 등록되어 있는 데이터이기 때문에, 기존에 다른 속성에서 computed의 데이터를 접근한 방식과 동일하게 this를 이용한 참조를 할 수 있다. 

 

더불어, 여러가지 state에서 불러오는 데이터가 필요하다면, 아래의 사진처럼 mapState()를 여러개 정의하여 사용하면 된다.

 

다음의 예시를 참고하자. 


4. mapActions() 

위에서 여러가지 Helper가 존재한다는 것을 언급하였다. 

이번에는 Actions를 Helper를 이용하여 간소하 하는 방법을 알아보자. 

 

아래의 예시코드가 기본적인 구조이다.

여기서 mapActions()를 사용하여 간소화를 진행해보자.

<script>
import { mapState } from 'vuex'
import Loader from '~/components/Loader'

export default {
  components: {
    Loader,
  },
  data() {
    return {
      imageLoading: true
    }
  },
  computed: {
    ...mapState('movie', [
      'theMovie',
      'loading'
    ])
  },
  created() {
    console.log(this.$route)
    this.$store.dispatch('movie/searchMovieWithId', {
      // movie/tt123456
      id: this.$route.params.id 
    })
  },
  methods: {
    requestDiffSizeImage(url, size = 700) {
      // url을 사용한 이미지 리사이징
      if(!url || url === 'N/A') { 
        this.imageLoading = false
        return '' 
      } 
      const src = url.replace('SX300', `SX${size}`)
      this.$loadImage(src)
        .then(() => {
          this.imageLoading = false
        })
      return src
    }
  }
}
</script>

 

mapActions()를 적용하면 다음과 같이 코드를 작성할 수 있다. 

<script>
import { mapState,mapActions } from 'vuex'
import Loader from '~/components/Loader'

export default {
  components: {
    Loader,
  },
  data() {
    return {
      imageLoading: true
    }
  },
  computed: {
    ...mapState('movie', [
      'theMovie',
      'loading'
    ])
  },
  created() {
    console.log(this.$route)
    //this.$store.dispatch('movie/searchMovieWithId', {
    // 위의 코드가 mapActions를 통해 아래처럼 this를 이용해 호출이 가능해졌다.  
    this.searchMovieWithId ({
      // movie/tt123456
      id: this.$route.params.id 
    })
  },
  methods: {
    ...mapActions('movie', [
      'searchMovieWithId'
    ]),

    requestDiffSizeImage(url, size = 700) {
      // url을 사용한 이미지 리사이징
      if(!url || url === 'N/A') { // 포스터 정보가 없어서 배경이미지를 대체해야 되는 경우 
        this.imageLoading = false
        return ''
      } 
      const src = url.replace('SX300', `SX${size}`)
      this.$loadImage(src)
        .then(() => {
          this.imageLoading = false
        })
      return src
    }
  }
}
</script>

위의 코드에서 가장 중요한 부분은 import를 이용하여 mapActions를 가져오는 부분이다. 

 

mapActions()를 이용하여 어떤 부분이 간소화 되었는지 확인할 수 있는 부분은 다음과 같다. 

클릭하면 확대됩니다. 

 

다만, 알아두어야 할 것이 있다. 

 

mapActions()로 코드가 대체 되기 전에는 $store의 dispatch() 함수를 이용하여 해당 메소드를 호출하는 것을 알 수 있다. 하지만, mapActions()를 사용하여 코드가 간소화 된 이후에는 searchMovieWithId() 라는 함수가 어디에서 넘어오는 것인지 한번에 확인하기가 쉽지 않다. 

 

이처럼, 코드를 helper를 이용하여 코드를 간소화 하는 것에는 장단점이 분명하다. 그러므로 Helper는 store에서 state를 가져오는 코드를 간소화 하는 것 외에 actions, mutations, getters 등의 코드를 간소화하기 위한 목적으로 사용하는 것은 권장하지 않는다.  

댓글