인생마커
article thumbnail
Published 2021. 11. 7. 23:41
Vuex Vue
 

Vuex가 무엇인가요? | Vuex

Vuex가 무엇인가요? Vuex는 Vue.js 애플리케이션에 대한 상태 관리 패턴 + 라이브러리 입니다. 애플리케이션의 모든 컴포넌트에 대한 중앙 집중식 저장소 역할을 하며 예측 가능한 방식으로 상태를

vuex.vuejs.org

 

vuex는 상태 관리 패턴 라이브러리입니다.

공통의 상태를 공유하는 컴포넌트가 있는 경우 단순함이 빠르게 저하된다.

vue는 다수의 컴포넌트를 사용하고 부모-자식 컴포넌트 사이에 데이터가 오고 갑니다.

 

아래 예시를 확인해 봅시다.

 

App.vue

<template>
  <Test @test-msg="log" />
  <span>
    {{ msg }}
  </span>
</template>

<script>
import Test from '~/components/TestCP'

export default {
  components:{
    Test
  },
  data(){
    return{
      msg:''
    }
  },
  methods:{
    log(appMsg){
      this.msg = appMsg
    }
  },
}
</script>

<style lang="scss">
body{
  background-color: #333;
  span{
    color: white;
  }
}
</style>

Test component

<template>
  <input
    type="text"
    v-model="msg" />
</template>

<script>
export default {
  data(){
    return{
      msg:''
    }
  },
  emits:[
    'testMsg'
  ],
  watch:{
    msg(){
      this.$emit('testMsg', this.msg)
    }
  }
}
</script>

<style lang="scss" scoped>
input{
  margin: 50px;
  width: 200px;
  height: 40px;
}
</style>

 

자식 컴포넌트에서 input으로 받은 데이터를 v-model 디렉티브를 사용해서 입력받은 값을 지속적으로 msg에 할당하고 있습니다.

 

그리고 watch 옵션으로 msg 값이 바뀌면 $emit에서 testMsg 이벤트로 this.msg 값이 부모 컴포넌트로 넘어갑니다.

 

testMsg 이벤트가 발생하면 부모 컴포넌트의 메소드 옵션에서 log 메소드가 실행되고 appMsg로 자식 컴포넌트에서 넘어온 값을 부모 컴포넌트의 msg 변수에 할당하고 있습니다.

 

 

이렇게 자식 컴포넌트의 input에서 받은 값을 부모 컴포넌트에서 출력하고 있습니다.

 

반대는 props를 사용합니다.

 

부모-자식간의 양방향 데이터 통신이 가능한 것입니다.

 

그렇다면 컴포넌트가 많아지고 부모-자식 관계가 아닌 컴포넌트 사이의 데이터를 전달해야만 하는 상황이 벌어졌다고 가정해봅시다.

 

 

 

Detail1 - Detail2 컴포넌트 사이에서 데이터를 주고 받으려면 부모인 Home이 매개체 역할을 해야합니다.

 

조금 수고롭지만 할만한거 같습니다.

 

그렇다면 Detail3과 Detail4의 경우를 생각해볼까요?

 

 

데이터 이동의 복잡도가 많이 올라갔습니다.

 

이런 문제를 해결하기 위에 vue 에서는 vuex를 제공합니다.

 

 

이렇게 애플리케이션의 모든 컴포넌트에 대한 중앙 집중식 저장소 역할을 합니다.

 

저장소에 저장되어 있는 데이터는 컴포넌트에서 직접 변경할 수 없습니다.

 

만약, 각 컴포넌트에서 저장소에 있는 데이터를 변경할 수 있다고 가정한다면 데이터 변경을 추적하기 힘들것입니다.

 

데이터를 변경할 수 있는 유일한 방법은 저장소에서 mutations라는 속성을 사용하는 것입니다.

 

+

다만 전역 상태의 무분별한 사용은 전체 애플리케이션의 성능 저하나 복잡도가 더 올라갈 수도 있습니다.

 

데이터는 되도록이면 상위에 위치한 컴포넌트에서 관리하고 하위로 가는 컴포넌트 일 수록 기능이나 데이터 관리가 단순해야 이상적인 모습이라고 개인적으로 생각하고 있습니다.

전역 상태는 다수의 컴포넌트의 불특정한 위치에서 지속적으로 사용되는 것이어야 더욱 효과적입니다.

 

예를 들면 account 정보나 페이지 언어 설정 정보 등이 있겠네요.


Start

vuex 실습을 위한 프로젝트를 간단하게 만들었습니다.

 

Header는 라우터가 아닌 컴포넌트입니다.

 

일괄 적용되야 하는 부분이니 App에서 직접 불러옵니다.

 

npm i vuex@next

 

반드시 main.js에 플러그인 사용을 명시해야 합니다.

 

import { createApp } from 'vue'
import App from './App.vue'
import router from './routes/index.js'
import store from './store'   // "
createApp(App)
  .use(router)
  .use(store)
  .mount('#app')

 

 

프로젝트에 store 폴더를 추가하고 index.js 를 만듭니다.

 

사용할 모듈을 스크립트 파일로 만들어서 관리할거기 때문에 import 해주고 모듈에서 명시하면 됩니다.

 

 

이렇게 파일 하나에서 모듈을 변수로 만들어서 사용해도 무방하지만 코드가 길어지고 모듈 또한 많아지면 역시 난해하기에 따로 자바스크립트 파일을 만들어서 관리하는 것이 좋습니다.

 

import {createStore} from 'vuex'
import home from './Home'
import about from './About'
export default createStore({
  modules:{
    home,
    about
  }
})

 

Store 모듈의 기본 구조는 다음과 같습니다.

 

export default{
  namespaced:true, // 모듈의 독립적 재사용 여부

  state:()=>({  //data와 같음
  }),

  getters:{  //종속성에 따라 캐쉬되는 계산된 속성
    }
  },
  
  mutations:{  // 저장소에 저장된 data를 바꿈
  },

  actions:{  // mutations에 대한 커밋을 한다. 비동기 작업이 포함됨.
  }
}

 

데이터의 흐름대로 살펴보겠습니다.

 

1. App.vue

<template>
  <Header />
  <RouterView />
</template>

<script>
import Header from '~/components/Header'
export default {
  components:{
    Header
  }
}
</script>
<style lang="scss">
  @import "~/scss/main"
</style>

 

헤더는 Home과 About을 오갈수 있는 링크만 걸어두었습니다.

 

2. HomeContnets (컴포넌트)

<template>
  <div class="container">
    <div>
      {{ msg }}
    </div>
  </div>
</template>

<script>
export default {
  data(){
    return{
      msg:'homeContents'
    }
  },
  created(){
    this.$store.dispatch('home/homeContent',this.msg)
  },
}
</script>

<style lang="scss" scoped>
  .container{
    background-color: orange;
    div{
      height: 3000px;
    }
  }
</style>

 

this.$store 로 vuex에서 제공하는 store객체를 확인할 수 있습니다.

 

 

이번에 사용할 commit과 dispatch가 보입니다.

 

commit은 store의 mutations를 실행할 때, dispatch는 actions를 실행할 때 사용합니다.

 

created(){
    console.log(this.$store)
    this.$store.dispatch('home/homeContent',this.msg)
  },

 

코드를 보면 앱이 생성될 때 dispatch 메소드로 store/home 모듈의 homeContent라는 actions를 실행하고 두 번째 인수로 homeContent의 data에서 할당되어 있는 msg를 넘겨주고 있습니다.

 

3. store/home (저장소)

export default{
  namespaced:true,
  state:()=>({
    msg:'',
  }),
  getters:{},
  mutations:{
    updateState(state, payload){ // payload에는 Search 값이 들어가있음 영화 10개 -> 객체형태로
      state.msg = payload
    }
  },
  actions:{
    homeContent({commit}, payload){
      commit('updateState',payload)
    }
  }
}

 

actions에서 homeContent가 실행되고 home 컴포넌트에서 넘어온 msg 인수를 payload 라는 매개변수로 받습니다.

 

그리고 mutations를 실행하기 위해 commit 메소드를 사용하고 첫 번째 인수로는 사용할 mutations 메소드 이름,
두 번째 인수로는 home 컴포넌트에서 넘어온 payload를 넘겨줍니다.

 

mutations는 state에 저장되어 있는 데이터를 바꿀 수 있는 유일한 속성입니다.

 

state의 msg라는 key 값을 가진 인자에 home에서 받아온 데이터가 들어있는 payload 를 할당합니다.

 

4. AboutContent

<template>
  <div class="container">
    <div>
      {{ msg }}
      {{ homeContent }}
    </div>
  </div>
</template>

<script>
export default {
  data(){
    return{
      msg:'AboutContents',
      homeMsg:'-'
    }
  },
  computed:{
    homeContent(){
      return this.$store.state.home.msg
    }
  }
}
</script>

<style lang="scss" scoped>
  .container{
    background-color: orange;
    div{
      height: 3000px;
    }
  }
</style>

 

this.$store.state.home.msg => 저장소의 데이터중 home 모듈에 있는 msg 라는 데이터를 가리킵니다.

 

가져온 데이터를 computed 속성의 homeContent로 return 해주고 템플릿 안에서 homeContent라는 변수이름으로 출력합니다.

 

노란색 섹션안에 homeContents라는 텍스트는 about에서 작성한 것이 아닌 저장소를 거쳐서 About 컴포넌트에 넘어온 텍스트 입니다.

 

확인을 위해서 HomeContents 안에 있는 글자를 바꿔줍니다.

 

HomeContents 컴포넌트

<template>
  <div class="container">
    <div>
      {{ msg }}
    </div>
  </div>
</template>

<script>
export default {
  data(){
    return{
      msg:'이 메시지는 Home에서 작성된 메시지 입니다.'
    }
  },
  created(){
    console.log(this.$store)
    this.$store.dispatch('home/homeContent',this.msg)
  },
}
</script>

<style lang="scss" scoped>
  .container{
    background-color: orange;
    div{
      height: 3000px;
    }
  }
</style>

 

여기는 home입니다.

 

 

about 컴포넌트에서도 home에서 작성한 데이터가 잘 넘어간걸 확인할 수 있습니다.

profile

인생마커

@Cottonwood__

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!