vueX와 헬퍼 정리

이명진·2022년 10월 10일
0

Vue 배우기

목록 보기
5/6

업무를 진행할때 잘썼었는데 최근에 vue를 안쓰다보니 많이 까먹긴했나본다. 다시 공부하고 정리해놓는다.

vuex에 대한 정리

공식문서를 보고 다시 정리하게 되었다. 모든 코드들은 공식문서에서 발췌했다.

vueX란 ?

상태관리 패턴 라이브러리 이다.
리액트의 redux와 비슷하다.

리액트는 단방향데이터 흐름이라서 리덕스를 사용해서 자식과 부모간의 데이터 통신도 하고
저장소에 변수를 저장하여서 정리를 쉽게 하기 위해 사용하였는데

Vue 는 자체적으로 emit 함수가 있어서 부모와 자식간의 소통이 가능하다.
하지만 역시 컴포넌트가 많아지고 기능이 많아질수록 이를 추적하기 쉽지 않다.
그래서 사용되는것 같다.

시작

저장소

리액트와 비슷하게 저장소가 있다. Store
기본적으로 애플리케이션상태를 보유하고 있는 컨테이너 이다. (공식문서)

일반 전역 객체와 다른점이 있다.

  1. Vuex store는 반응형 입니다. Vue 컴포넌트는 상태를 검색할 때 저장소의 상태가 변경되면 효율적으로 대응하고 업데이트합니다.
  2. 저장소의 상태를 직접 변경할 수 없습니다. 저장소의 상태를 변경하는 유일한 방법은 명시적인 커밋을 이용한 변이 입니다. 이렇게하면 모든 상태에 대한 추적이 가능한 기록이 남을 수 있으며 툴을 사용하여 앱을 더 잘 이해할 수 있습니다.
    (공식문서)

1번 문제를 봤을때 vue의 상태 변경에 대해서 효율적으로 대응하고 업데이트한다고 한다. 이를통해 성능개선의 효과가 있을것 같다.
2번째 다른점은 리덕스와 비슷하다. 바로 변경이 불가능하고 매개체를 통해서 변경 시켜야 한다. 매개체가 있어야 확실히 어떤 변화를 줬는지 파악하기 빠르고 추적도 용이하다.

생성

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  }
})

위와 같은 코드로 저장소를 생성한다.
state: 변수를 지정하는 곳이다.
mutations: 변수를 변경하기 위한 함수들을 모아놓는 곳이다.

이를 통해 commit메소드로 상태를 트리거 할수 있다. 리덕스의 action과 같다.
store.commit(‘increament’) 로 사용된다 .
이렇게 하면 mutations에서 지정해놓은 increament 가 실행되고 변수를 변경할수 있다.

VueX state값을 가져오기

변수들을 가져오기 위해서는 각 컴포넌트의 computed에서 가져올수 있다.

첫번째로 모든 자식 컴포넌트에 저장소를 주입하는 메커니즘을 사용하여서 store를 알려준다.
코드들은 공식문서에서 발췌했다.

const app = new Vue({
  el: '#app',
  // "store" 옵션을 사용하여 저장소를 제공하십시오.
  // 그러면 모든 하위 컴포넌트에 저장소 인스턴스가 삽입됩니다.
  store,
  components: { Counter },
  template: `
    <div class="app">
      <counter></counter>
    </div>
  `
})

app.vue 처럼 모든 루트에 store를 지정해준다.

각 컴포넌트에서 아래 코드 처럼 state를 가져온다.

const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
    count () {
      return this.$store.state.count
    }
  }
}

this.$store.state.count 딱봐도 너무 길고 쓰기 불편하다.
그래서 등장한데 헬퍼 시스템이다.

헬퍼

헬퍼는 vueX를 쓰기 쉽게 도와준다. 거의 필수로 사용되어야 한다.

mapState

state값을 가져오기 편리하게 해주는 헬퍼의 기능이다.


// 독립 실행 형 빌드에서 헬퍼가 Vuex.mapState로 노출됩니다.
// 일단 헬퍼를 임포트 해준다. 
import { mapState } from 'vuex'

export default {
  // ...
  computed: mapState({
    // 화살표 함수는 코드를 매우 간결하게 만들어 줍니다!
    count: state => state.count,

    // 문자열 값 'count'를 전달하는 것은 `state => state.count`와 같습니다.
    countAlias: 'count',

    // `this`를 사용하여 로컬 상태에 액세스하려면 일반적인 함수를 사용해야합니다
    countPlusLocalState (state) {
      return state.count + this.localCount
    }
   // 바로 사용 
 'count'

  })
}

mapState 안에서 화살표함수를 바로 사용해서 가져올수 있고 가져온것에 이름을 지정해서 사용할수도 있다.
그리고 this를 사용하기 위해서는 화살표 함수를 사용하지 않으면 된다.

바로 사용하기 위해서는 그냥 바로 가져오면된다. 바로 사용하면 this.count로 바로 접근이 가능하다.

Getters

저장소 값을 가져올때 어느 컴포넌트에서는 state를 한번더 가공하고 사용해야 할수도 있다.
이를 위해서 컴포넌트 별로 state를 가져오고 계산을 할것이 아니라 바로 저장소에서 계산해서 이름을 부여해서 전달해주면된다.

const store = new Vuex.Store({
  state: {
    todos: [
      { id: 1, text: '...', done: true },
      { id: 2, text: '...', done: false }
    ]
  },
  getters: {
    doneTodos: state => {
      return state.todos.filter(todo => todo.done)
    }
  }
})

위의 코드처럼 바로 계산을 한 값을 doneTodos 로 이름을 주었다.

각 컴포넌트에서 사용하기 위해서는 computed 속성에서 가져와서 사용할수 있다.

computed: {
  doneTodosCount () {
    return this.$store.getters.doneTodosCount
  }
}

직접 함수처럼 매개변수를 지정해서 원하는 값을 도출하도록 할수도 있다.

getters: {
  // ...
  getTodoById: (state) => (id) => {
    return state.todos.find(todo => todo.id === id)
  }
}
//컴포넌트에서 사용 
store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }

위와 같은 코드로 사용하게 되면 호출될때마다 getter가 실행되며 결과가 캐시되지 않는다.
성능에 문제가 될것 같다.

헬퍼 mapGetters

getter를 쉽게 쓰기 위해 헬퍼를 사용한다.
mapGetters([]) 로 사용하며 세미콜론을 사용하여 이름을 가져오면 그대로 사용이 가능하고
객체로 키와 값으로 가져오면 새로운 이름을 맵핑할수 있다.

mutations

위에서 조금 언급했던 것처럼 state를 변경할수 있는 함수들을 모아놓은 거라고 생각하면된다.
각 컴포넌트에서는 store.commit(‘mutations 변수 이름 ’) 으로 사용이 가능하다.

페이로드

변이에 대해 payload 라고하는 store.commit에 추가 전달인자를 사용 할 수 있다.

mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}

형태는 위와 같고 매개변수로 넣을수 있는데 페이로드는 객체로 사용하는 것을 권장한다.
그래야 한번에 이해 하기 좋다고 한다.

store.commit('increment', {
  amount: 10
})

리덕스 강의에서 들은것처럼 mutations의 함수 이름들은 상수로 지정하는게 좋다.
상수로 지정해야 글자 에러(스펠링 철자 에러)가 발생하지 않기 때문이다.

헬퍼 mapMutations

import { mapMutations } from 'vuex'

export default {
  // ...
  methods: {
    ...mapMutations([
      'increment' // this.increment()를 this.$store.commit('increment')에 매핑합니다.
    ]),
    ...mapMutations({
      add: 'increment' // this.add()를 this.$store.commit('increment')에 매핑합니다.
    })
  }
}

다른 것과 마찬가지로 매핑과 바로 사용이 가능하다.

액션

Mutation과 비슷하다. mutation은 동기로서 작용하지만
액션은 비동기로서 작업이 가능하다.

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      context.commit('increment')
    }
  }
})

액션은 commit 으로 mutation의 함수들을 사용할수 있다.

그리고 사용할때는 dispatch를 이용한다.

store.dispatch('increment')
Dispatch 는 commit과 마찬가지로 페이로드를 가질수 있다.

액션은 비동기 작업이 가능하여 api호출 같은 여러개의 변이를 커밋할수 있다.

액션 내부 자체에 promise를 반환 처리 할수 있다.

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

Async/await 도 당연히 가능하다.

actions: {
  async actionA ({ commit }) {
    commit('gotData', await getData())
  },
  async actionB ({ dispatch, commit }) {
    await dispatch('actionA') // actionA가 끝나기를 기다립니다.
    commit('gotOtherData', await getOtherData())
  }
}

헬퍼 mapActions

컴포넌트 내부에서는 this.$store.dispatch('xxx') 이렇게 사용이 가능하다.
헬퍼를 사용하면

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

      // mapActions는 페이로드를 지원합니다.
      'incrementBy' // this.incrementBy(amount)를 this.$store.dispatch('incrementBy', amount)에 매핑
    ]),
    ...mapActions({
      add: 'increment' // this.add()을 this.$store.dispatch('increment')에 매핑
    })
  }
}

이처럼 사용가능하다. 페이로드를 지원해서 페이로드를 작성안해도 된다.

profile
프론트엔드 개발자 초보에서 고수까지!

0개의 댓글