NodeJS

[NodeJs/VueJs] 상위, 하위 컴포넌트간 데이터 전달 방법

Question영 2019. 11. 7. 15:58

안녕하세요.

 

이번에는 Vue 를 사용하면서 저를 많이 혼란스럽게 했던 기능 중 주요 기능인

 

상위, 하위 컴포넌트간 데이터 전달 방법에 대해 살펴보려고 합니다.

 

오늘도 미래의 저에게 도움이 될수 있기를!

 

요 근래 Vue 를 공부하는 중 상위, 하위 컴포넌트간 데이터 통신이 자주 필요했습니다.

 

주고 받을수 있는 방법은 정리해보자면 다음과 같았습니다.

 

  • this.$root 혹은 this.$parent 를 이용
  • v-bindprops, v-on 이벤트와 $emit 를 이용
  • v-model 를 이용
  • EventBus 를 이용
  • vuex 의 store 공통객체를 이용

 

전부 다 Vue에서 데이터를 전달하고 관리하기 용의한 방법들입니다. (이렇게나 많네요!)

 

여기서 vuex 를 이용하는 방법은 글로벌한 공통 상태값을 관리하기에 적합하나

 

한정된 컴포넌트간의 통신에는 부적합하여 패스.

 

EventBus 로 가능하지만 자주 사용하게 되면 나중에 이벤트를 추적 관리하기 힘들어지기 때문에 패스!

 

남은 방법들을 검토했습니다.

 

# App.vue

<template>
  <div id="app">
    <child></child>
  </div>
</template>

<script>
import Child from '@/components/Child.vue'
export default {
  name: 'App',
  data: function () {
    return {
        rootData: 10
    }
  },
  components: {
    // Child 컴포넌트를 하위 컴포넌트로 등록
    'child': Child
  }
}
</script>

<style>
  ...
</style>

# Child.vue

<template>
  <div>
    Child
    <child-child></child-child>
  </div>
</template>

<script>
import ChildAndChild from '@/components/ChildAndChild.vue'
export default {
  name: 'Child',
  data: function () {
    return {
        childData: 20
    }
  },
  components: {
    // Child 컴포넌트를 하위 컴포넌트로 등록
    'child-child': ChildAndChild
  }
}
</script>

# ChildAndChild.vue

<template>
  <div>
    Child And Child
    <button @click="showRootLog">Root 데이터 조회</button>
    <button @click="showParentLog">Parent 데이터 조회</button>
  </div>
</template>

<script>
export default {
  name: 'ChildAndChild',
  methods: {
    showRootLog: function () {

    },
    showParentLog: function () {

    }
  }
}
</script>

 

this.$root 와 this.$parent

 

3개의 예제에서 ChildAndChild.vue 에 다음과 같이 작성해봅시다.

 

<template>
  <div>
    Child And Child
    <button @click="showRootLog">Root 데이터 조회</button>
    <button @click="showParentLog">Parent 데이터 조회</button>
  </div>
</template>

<script>
export default {
  name: 'ChildAndChild',
  methods: {
    showRootLog: function () {
      console.log('rootData', this.$root.rootData)
    },
    showParentLog: function () {
      console.log('childData', this.$parent.childData)
    }
  }
}
</script>

그러면 App.vueChild.vue 에 정의된 데이터가 콘솔창에 조회 될 것 입니다.

이런식으로 조회도 가능하지만 수정도 가능하기 때문에 제일 간단하게 사용할수 있는 장점도 있으나 단점도 있습니다.

앞서 말한 EventBus 와 동일한 이유인데요.

프로젝트가 작고 상관없으나 프로젝트가 커지게 되면 이를 이용한 수정을 했을때 이벤트 추적이 힘들어질수 있을수 있습니다.

그래서 개인적으로 권장하고 싶지는 않지만 가장 단순하게 컴포넌트간 데이터를 활용할수 있는 방법입니다.

v-bind 와 props, v-on 이벤트와 $emit 을 이용

# Child.vue

<template>
  <div>
    Child
    <child-child :send-data="childData" @event-data="setChildData"></child-child>
  </div>
</template>

<script>
import ChildAndChild from '@/components/ChildAndChild.vue'
export default {
  name: 'Child',
  data: function () {
    return {
        childData: 20
    }
  },
  components: {
    // Child 컴포넌트를 하위 컴포넌트로 등록
    'child-child': ChildAndChild
  },
  mehtods: {
    setChildData (data) {
      this.childData = data
      console.log(this.childData)
    }
  }
}
</script>

# ChildAndChild.vue

<template>
  <div>
    Child And Child
    <button @click="showParentLog">Parent 데이터 조회</button>
    <button @click="sendEditData">Parent 데이터 수정</button>
  </div>
</template>

<script>
export default {
  name: 'ChildAndChild',
  props: ['sendData']
  methods: {
    showParentLog: function () {
      console.log('child 데이터', this.sendData)
    },
    sendEditData: function () {
      console.log('child 데이터 수정 후 전달')
      let changeData = this.sendData + 30
      this.$emit('event-data', changeData)
    }
  }
}
</script>

 

두 묶음(?) 방법의 활용도는 다음과 같습니다.

 

  • v-bind + props : 상위 컴포넌트에서 하위 컴포넌트로의 데이터 전달
  • v-on + $emit : 하위 컴포넌트에서 상위 컴포넌트로 데이터 전달

 

두가지를 동시에 사용하게 되면 이런 시나리오도 가능하게 됩니다.

 

  • 하위 컴포넌트로 데이터를 전달한다.
  • 하위 컴포넌트에서 전달 받은 데이터를 이용하여 가공을 한다.
  • 가공된 데이터를 상위 컴포넌트에 전달하여 갱신한다.

 

간단하게 조회와 수정, 갱신이 가능하게 되는 거죠.

 

이 방법을 사용하게 되면 인과 관계가 명확하게 되므로 프로젝트가 커지더라도 이벤트의 추적이 용의하게 됩니다.

 

그런데 이 방법을 하나의 속성을 이용하여 최적화가 가능한 방법이 있습니다.

 

v-model 를 이용

 

이전 예제 코드를 다음과 같이 수정합니다.

 

# Child.vue

<template>
  <div>
    Child
    <child-child v-model="childData"></child-child>
    <button @click="showDataLog">데이터 조회</button>
  </div>
</template>

<script>
import ChildAndChild from '@/components/ChildAndChild.vue'
export default {
  name: 'Child',
  data: function () {
    return {
        childData: 20
    }
  },
  components: {
    // Child 컴포넌트를 하위 컴포넌트로 등록
    'child-child': ChildAndChild
  },
  mehtods: {
    showDataLog () {
      console.log(this.childData)
    }
  }
}
</script>

# ChildAndChild.vue

<template>
  <div>
    Child And Child
    <button @click="showParentLog">Parent 데이터 조회</button>
    <button @click="sendEditData">Parent 데이터 수정</button>
  </div>
</template>

<script>
export default {
  name: 'ChildAndChild',
  model: {
    prop: 'sendData',
    event: 'event-data'
  }
  props: ['sendData']
  methods: {
    showParentLog: function () {
      console.log('child 데이터', this.sendData)
    },
    sendEditData: function () {
      console.log('child 데이터 수정 후 전달')
      let changeData = this.sendData + 30
      this.$emit('event-data', changeData)
    }
  }
}
</script>

 

전 방법과 다른 점은 다음과 같습니다.

 

  • 상위 컴포넌트에서 하위 컴포넌트를 설정할때 속성이 v-model 하나로 축소
  • 하위 컴포넌트에서 model 속성 객체를 추가하여 설정

 

Child 컴포넌트에서 버튼으로 로그를 조회해보면

 

childData 결과는 이전과 동일하게 수정 되는 것을 확인하실수 있습니다.

 

v-model 은 공식 홈페이지에서도 주로 input 태그나 radio box 등과 같은

 

반응형 컴포넌트에서 사용을 하라고 주로 소개하고 있었으며

 

그래서 그런지 v-bind 와 v-on 이 v-model 로 최적화 하는 과정의 데이터 설정과 흐름이 많이 혼란스러웠습니다.

 

간략하게 나마 정리하니 명확하게 정리가 되네요.

 

그럼 포스팅 마치겠습니다.

반응형