탱구탱구 개발자 일기

 

초창기 자바스크립트 프레임워크에선 하나의 화면 = 하나의 view로 간주

  • 해당 화면 영역에 있다면 해당 데이터 참조 가능

Vue.js의 경우 하나의 화면 = 하나 혹은 다수의 컴포넌트

 

vue.js의 중요한 특징은 컴포넌트마다 고유한 스코프(유효 범위)가 존재. 즉 컴포넌트끼리 직접 참조가 불가능하다.

따라서 vue에서 자체적으로 정의한 컴포넌트 데이터 전달 방법을 이용해 통신해야 한다.

 

Vue는 컴포넌트 단위로 화면이 구성되고 하나의 컴포넌트는 자식 컴포넌트를 갖게 될 수 있다. 이러한 경우를 부모-자식 컴포넌트 관계 or 상-하위 컴포넌트 관계라고 한다.

화면을 구성하다보면 이렇게 구성할 경우가 많은데 그 과정에서 서로 데이터가 공유될 때가 많다.

 

상-하위 컴포넌트 관계

Vue.js에서 부모-자식 컴포넌트 관계는 props는 아래로, events 위로 라고 요약 할 수 있다. 부모는 props를 통해 자식에게 데이터를 전달하고 자식은 events를 통해 부모에게 메시지(이벤트)를 보낸다.

 

기본적으로 Vue는 단방향 데이터 흐름(One-way Data Flow)의 특징을 갖는다. 이는 컴포넌트의 단방향 통신을 의미하는데 컴포넌트 간 데이터 전달 시 항상 상위 컴포넌트에서 하위 컴포넌트로 데이터가 전달되도록 구조화되어 있다는 것을 말한다. 따라서 상-하위 컴포넌트 구조에선 하위 컴포넌트에서 상위 컴포넌트로 데이터 전달은 기본적으로 제한되어 있다.

 

 

먼저 props를 이용해 상위컴포넌트에서 하위컴포넌트로 데이터를 전달하는 코드를 작성해 보겠다.

 

[Props : 상위 -> 하위컴포넌트]

 

다음과 같이 컴포넌트 관계 및 요구사항을 정의했다.

  • 상위 컴포넌트 : App.vue
  • 하위 컴포넌트 : Home.vue
  • 요구사항
    • props를 통해 App 컴포넌트에서 Home 컴포넌트로 데이터 전달
    • Home 컴포넌트에서 props로 전달된 데이터를 받아서 버튼 tag의 href 속성값을 변경
    • 네이버로 연결

 

컴포넌트 구조

코드 구현 과정은 다음과 같다.

  1. 하위 컴포넌트인 Home.vue에서 props로 받을 props 속성 이름을 정의한다.
  2. 아래와 같이 상위컴포넌트에 정의한 하위컴포넌트 태그에 v-bind 속성을 추가한다.
<하위컴포넌트 v-bind:[하위컴포넌트에서 정의한 props 속성이름]="상위컴포넌트에서 전달할 data 속성key값"></하위컴포넌트>

[Home.vue]

<template>
  <v-btn :href="path">네이버연결</v-btn> <!-- v-bind를 통해 href 속성 조작(path) -->
</template>

<script>

export default {
  props: ['linkInfo'], // 하위컴포넌트에서 linkInfo라는 이름으로 데이터를 받겠다라고 정의
  data() {
    return {
      path: this.linkInfo //상위컴포넌트에서 linkInfo라는 이름으로 넘어온 props value를 path에 대입
    }
  }
}
</script>

 

[App.vue]

<template>
  ...코드 생략
  <v-app>   
    <v-main>
     <!-- 하위컴포넌트에서 정의한 props 이름인 linkInfo에 전달할 data 속성 value 설정-->
      <Home v-bind:linkInfo="path"></Home>
    </v-main>
  </v-app>
</template>
<script>
import Home from "@/components/preset/Home";

export default {
  name: 'App',

  components: {
    Home
  },

  data: () => ({
    path: 'https://naver.com' // props를 통해 하위컴포넌트에 전달할 데이터
  }),
};
</script>
<style scoped>

</style>

[결과]

네이버연결버튼 href 설정

사진에서 처럼 네이버연결 버튼에 props를 통한 href 속성이 변경되어 링크연결이 잘되어 있다.

 

vue-devtools를 통해서도 확인해보면 아래와 같이 props가 잘 전달되는 것을 알 수 있다.

 

[APP - 상위 컴포넌트]

[Home - 하위 컴포넌트]

  • 아래와 같이 상위컴포넌트에서 전달한 props를 잘 가져와서 data 속성의 path 객체에 잘 넣음

 

다음으로 event를 이용해 하위컴포넌트에서 상위컴포넌트로 통신 방법에 대해 살펴보도록 하자. 서두에 설명했던 것처럼 Vue의 단방향 데이터 흐름 특성으로 인해 하위 -> 상위 컴포넌트로의 데이터 전달은 제한되어있다. 하지만 이벤트를 통해 상위 컴포넌트의 method를 수행할 수 있다.

 

[event : 하위 -> 상위컴포넌트]

 

다음과 같이 컴포넌트 관계 및 요구사항을 정의했다.

  • 상위 컴포넌트 : App.vue
  • 하위 컴포넌트 : InputArea.vue
  • 요구사항
    • InputArea에서 event를 정의하고 발생시킨다.
    • InputArea의 이벤트 발생 버튼을 누른다
    • 상위 컴포넌트인 App에서 발생한 이벤트를 v-on 디렉티브를 통해 '이벤트명'으로 수신할 수 있다.
    • 수신한 이벤트에 연결된 App 컴포넌트의 Alert method를 호출한다.
    • Alert 확인

[하위 컴포넌트 : InputArea.vue]

<template>
  <v-container fluid>
    <v-text-field label="검색바" v-model="inputText"></v-text-field>
    <!-- 정의된 이벤트를 호출할 버튼 생성 -->
    <v-btn class="ml-2" v-on:click="transferEvent">이벤트호출</v-btn>
  </v-container>
</template>

<script>
import EventBus from "@/eventBus";

export default {

  data () {
    return {
      inputText: ''
    }
  },
  name: "InputArea",
  methods: {
    transferEvent: function () { // 버튼 클릭시 'show-log'라는 이벤트 발생
      this.$emit('show-log');
    }

  }
}
</script>

<style scoped>

</style>

[상위 컴포넌트 : App.vue]

<template>
  <v-app id="inspire">
  ...코드 생략
    <v-main>
    <!-- v-on을 통해 하위컴포넌트 이벤트 지정 및 발생 시 호출될 상위 컴포넌트 method(AlertMsg) 지정 -->
      <InputArea v-on:show-log="AlertMsg"></InputArea>  
    </v-main>  
  </v-app>
</template>
<script>
import InputArea from "@/components/preset/InputArea";

export default {
  name: 'App',

  components: {
  ... 코드생략
    InputArea
  },

  data: () => ({
    drawer: null,
    path: 'https://naver.com'
  }),
  methods : {
    AlertMsg : function () { // 하위컴포넌트에서 발생한 이벤트 수신 시 호출할 method
      alert("Alert 이벤트 발생"); 
    }
  }
};
</script>
<style scoped>

</style>

 

[결과]

 

 

하위 -> 상위 컴포넌트 이벤트 전달

 

VueDevtools에서도 이벤트가 발생한 것을 알 수 있다.

 

 

지금까지 상-하위 컴포넌트 통신 방법을 살펴보았다.

 

Vue.js 공식 문서에도 props 사용방법, event 관련 예제가 나와있지만 단순한 테스트 코드가 아니라 실제 사용할 법한 화면 기능에 구현해보면서 좀 더 이해가 잘 된 것 같다. 이론적인 부분은 vue.js 공식 문서를 참고하면 좋을 것 같다.

 

[참고]

https://kr.vuejs.org/v2/guide/components.html#Props%EB%A1%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A0%84%EB%8B%AC%ED%95%98%EA%B8%B0

 

컴포넌트 — Vue.js

Vue.js - 프로그레시브 자바스크립트 프레임워크

kr.vuejs.org

 

 

이 글을 공유합시다

facebook twitter kakaoTalk kakaostory naver band
loading