[TIL] mitt, Vuex

ㅜㅜ·2023년 4월 15일
1

Today I learn

목록 보기
77/77
post-thumbnail

🟢 mitt

mitt는 특정 이벤트를 만들어서 서로 다른 컴포넌트들에 송출하는 라이브러리이다. props나 event emit으로는 부족한 떨어진 컴포넌트 간에 데이터를 주고 받는 방법이라고 할 수 있다.
Vue2에서는 EventBus가 있었다고 하는데, Vue3에서는 mitt를 사용하는듯.

🐝 install

npm install mitt

🐝 setting

//main.js
import { createApp } from 'vue'
import App from './App.vue'
import mitt from 'mitt'

const emitter = mitt();
const app = createApp(App);
//globalProperties는 모든 컴포넌트에서 사용할 변수들이 입력된 object
//아래와 같이 입력해주면 emitter를 꺼내서 사용하기 쉽게 만들어주는 과정이라고 생각하면 될듯 
app.config.globalProperties.emitter = emitter
app.mount('#app')

🍯 use

  • 이벤트를 수신할 때는 (듣는 쪽) on 매서드를 사용한다.
  • 이벤트를 방출할 때는 (보내는 쪽) emit 매서드를 사용한다.
  • 이벤트에 이름을 지을 수 있어서, 방출하는 쪽에서 지은 이름을 수신하는 쪽에서 호출해서 이벤트를 받을 수 있음.

어떤 버튼을 눌렀을 때 해당 요소에서 받은 데이터를 다른 컴포넌트들에서 사용하고 싶은 경우가 있다고 하면 아래와 같이 emitter를 사용할 수 있다.

//방출하는 쪽 컴포넌트 
<template>
<button @click="setLocation(location)"/>
</template>

<script>
  props:{
    location:String,
  },
    methods:{
      setLocation(a){
        //파라미터 : 전송할 때 사용할 이름 , 함께 전송할 데이터 
        this.emitter.emit("send",a)
      }
    }
  
</script>

    
 //받는 쪽 컴포넌트의 script 태그 내부 
 //보통 mounted 안에서 수신 받는다고 함 
 //getlocation이라는 컴포넌트 자체 데이터가 있다고 가정 
    mounted(){
      //전송 받은 데이터는 두번째 인자인 콜백의 파라미터로 받아볼 수 있음 
      this.emitter.on("send",(data)=>{
        this.getlocation = data;
      }
    }

(혼자서 예시 코드를 작성해보려고 하다보니 좀... 미흡한 부분이 있다.)

Vue 라이프사이클 훅+에는 mounted, updated, unmounted 등이 있음. 더 자세한 것은 공식 문서 참고.


🟢 Vuex

Vuex는 store, actions 같은 이름들이 Redux가 생각나기도 했고...
mutations로 store에 담긴 state를 변경할 수 있다는 점은 recoil이 생각나기도 했다.
아무튼 실습할 때 내내 props로 이리 옮기고 저리 옮기고 하다가 상태 관리 라이브러리를 사용하니 확실히 좋더라...

🐝 install

npm install vuex@next --save

🐝 setting

//src 폴더 내부에 store.js 파일 생성

import { createStore } from 'vuex'

const store = createStore({
  state(){
    return {
      //여기에 저장할 데이터들을 키, 값 형식으로 담아준다. 
    }
  },
})

export default store

___________________________

//main.js 파일에 해당 코드 추가 
import store from './store.js'

//참고로 app은 let app = createApp(App) 이거임 
app.use(store).mount('#app')

🍯 Use

🐝 state 사용하기

  • store에 저장된 state를 vue 파일에서 불러오려면 {{ $store.state.상태이름 }}
  • 함수나 라이프사이클 훅에서 사용할 때는 앞에 this를 붙여서 this.$store.state.상태이름 와 같이 사용.

🐝 state 변경하기

  • store에 저장된 state는 직접 바꾸면 안 됨. 예기치 못한 변경이 있을 때 디버깅이 힘들어지기 때문에.
  • mutation 함수를 통해 변경해야 함.
//여기는 store.js 파일 
const store = createStore({
  state(){
    return {
      age: 33
    }
  },
  mutations:{
    //getOld는 age라는 state를 1씩 증가시키는 상태 변경 함수 
  	getOld(state){
      state.age++;
    }
  }
})

export default store

특정 버튼 요소를 눌렀을 때 age가 1씩 증가하고 싶게 만들면 아래와 같다.

<button @click="$store.commit('getOld')"></button>

참고로 mutation 함수는 payload를 받아서 처리할 수도 있는데,
예를 들어 위 코드에서 age를 증가시키는 수를 두번째 인자로 받을 수도 있음.

//getOld가 아래와 같고
getOld(state,n){
	state.age += n
}

//실 사용시에는 아래와 같이 작성할 수 있음 
//10씩 증가한다 
<button @click="$store.commit('getOld', 10)"></button>

🐝 ajax with Vuex

ajax 통신을 할 때는 mutation이 아닌 actions 내부에 만든 함수를 통해서 처리한다.
(mutation 함수는 항상 동기적이어야 한다.)

아래 예제를 보면 기본적으로 actions에서 만들어진 함수는 context라는 것을 받아올 수 있고,
context에서 mutation 함수를 호출할 때처럼 .commit을 이용해 mutation 함수를 호출할 수 있다.
즉, actions 함수에서 데이터 통신을 통해 받아온 데이터를 context를 이용해 mutation 함수를 통해 특정 state에 저장시켜줄 수 있음.

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

actions 함수를 가져와서 사용하고 싶을 때는 $store.dispatch('increment')와 같이 사용해야 하고,
컴포넌트 내에서 this.$store.dispatch('increment'),와 같이 사용해야 함.

🐝 mapState, mapMutations, mapActions...

위 코드에서도 느낄 수 있겠지만, state와 mutation을 사용하기 위해서는 적어야하는 코드가 많다.
mapState, mapMutations, mapActions를 이용하면 훨씬 간단하게 상태나, mutation, action 함수를 불러올 수 있다.

mapState는 컴포넌트 내의 computed 속성 내에,
mapMutations나 mapActions는 methods 속성 내에서 사용할 수 있다.

import { mapState } from 'vuex'

//배열로 작성할 수 있고
export default {
  computed : {
  ...mapState(['상태 이름', '상태 이름'...])
}
}

//객체로 작성해 이름을 다르게 해서 가져올 수도 있음
export default {
  computed : {
   ...mapState({ 내가지은이름 : '원래 상태 이름'})
}
}

위와 같이 작성하면 데이터 바인딩 시에 {{상태 이름}}이나 {{내가지은이름}}과 같이 짧게 사용할 수 있게 된다.

mutations, actions도 비슷하게 작성하면 되지만, methods 안에 작성한다.

import { mapMutations } from 'vuex'

export default {
  // ...
  methods: {
    ...mapMutations([
      'increment', // map `this.increment()` to `this.$store.commit('increment')`

      // `mapMutations` also supports payloads:
      'incrementBy' // map `this.incrementBy(amount)` to `this.$store.commit('incrementBy', amount)`
    ]),
    ...mapMutations({
      add: 'increment' // map `this.add()` to `this.$store.commit('increment')`
    })
  }
}
import { mapActions } from 'vuex'

export default {
  // ...
  methods: {
    ...mapActions([
      'increment', // map `this.increment()` to `this.$store.dispatch('increment')`

      // `mapActions` also supports payloads:
      'incrementBy' // map `this.incrementBy(amount)` to `this.$store.dispatch('incrementBy', amount)`
    ]),
    ...mapActions({
      add: 'increment' // map `this.add()` to `this.$store.dispatch('increment')`
    })
  }
}
profile
다시 일어나는 중

0개의 댓글