본문 바로가기
Study

[Vue.js] Vue (MVVM, Props와 Event, v-model)

by 안자두 2023. 5. 24.

 

Vue란?

Vue는 사용자 인터페이스를 구축하기 위한 JavaScript 프레임워크다.
표준 HTML, CSS, JavaScript를 기반으로 구축되며, 단순한 것부터 복잡한 것까지 사용자 인터페이스를 효율적으로 개발할 수 있는 컴포넌트 기반의 프로그래밍 모델을 제공한다.

 


 

선언적 렌더링과 반응성

Vue에는 표준 HTML을 템플릿 문법으로 확장하여 JavaScript 상태를 기반으로 선언적 렌더링을 할 수 있으며, JavaScript 상태 변경을 추적하고, DOM 요소에 연결되어 변경이 발생하면 DOM을 효율적으로 자동 업데이트 하는 반응성이라는 두 가지 핵심 기능이 있다.

이를 바탕으로 Vue는 접근하기 쉽고(Approachable), 변하기 쉬우며(Versatile), 효율적이며(Performant), 유지보수할 수 있고(Maintainable) 테스트할 수 있다(Testable)는 특징을 갖고 있다.

 


 

MVVM pattern에서의 Vue

MVVM pattern

MVVM 패턴은 Model, View, Model View로 구성되어 있다. 간단하게 화면 앞단의 화면 동작 관련 로직과 뒷단의 DB 데이터 처리 및 서버 로직을 분리하고, 뒷단에서 넘어온 데이터를 Model에 담아 View로 넘어가는 중간 지점을 View Model로 둔 패턴이다.

Vue는 부분적으로 MVVM 패턴에 영감을 받았는데 ViewModel Layer에 해당하는 화면단 라이브러리가 바로 Vue이다.

 

MVVM 의존성

Vue는 인스턴스를 생성하여 DOM 화면에서 사용되는 데이터를 관리하는 View를 위한 Model인 View Model로써 사용된다.
View는 View Model을 알고, View Model은 Model을 알지만, Model은 View Model을 알 수 없고, View Model은 View를 알 수 없는 단방향으로만 의존성이 존재하기 때문에 View와 Model 사이에는 의존성이 없다.

또한 한쪽으로만 의존성이 존재하기 때문에 모듈로 분리하기가 쉽고, 모듈화에 적합한 만큼 테스트하기도 수월하다.

 


 

Vue.js 사용하기

Vue.js를 시작하는 방법에는 크게 CDN, NPM, CLI 3가지가 있다.

자세한 방법과 비교는 이전 글에서 포스팅해 두었다.

2023.05.22 - [Study] - [Vue.js] Vue 시작하기 (CDN vs NPM vs CLI)

 

[Vue.js] Vue 시작하기 (CDN vs NPM vs CLI)

공식적으로 Vue를 설치하는 방법에는 크게 세 가지가 있다. 1. 직접 script에 추가하는 CDN 2. NPM을 이용한 설치 3. 단일 페이지 애플리케이션을 빠르게 구축할 수 있는 CLI 각각의 방법으로 직접 설치

ktmihs.tistory.com

 

chrome에서 확장 프로그램 플러그인으로 제공하는 Vue devtools를 사용하여 component나 data, event, vuex를 쉽게 확인할 수 있다.

https://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd

 

Vue.js devtools

Browser DevTools extension for debugging Vue.js applications.

chrome.google.com

이 페이지에서 확장 프로그램을 설치할 수 있다.

설치한 후, 개발자 도구를 열면 Vue 패널을 볼 수 있다.

아래에서 사용한 예시인데, 이처럼 컴포넌트를 확인하거나 데이터를 직접 변경하는 등의 작업을 수행할 수 있다.

 


 

단방향 데이터 흐름

컴포넌트는 화면의 영역을 구분하여 개발할 수 있는 뷰의 기능을 말한다. 이는 코드의 재사용성을 높여주며, 빠르게 화면을 제작할 수 있게 해준다.

컴포넌트 간 통신은 기본적으로 React처럼 부모에서 자식으로 단방향 데이터 흐름을 가진다. 부모에서 자식으로만 데이터를 Props로 내릴 수 있으며, 자식에서 부모로는 Event를 발생시킬 수 있다.

만약 같은 레벨의 컴포넌트끼리 값을 주고받으려면, 상위 컴포넌트로 Event를 발생시켜 다시 하위 컴포넌트로 Props를 내려주어야 한다.

Vue component data flow

 

Vue의 컴포넌트는 각각 고유한 데이터 유효 범위를 갖기 때문에 이와 같은 규칙을 따라야 데이터를 주고받을 수 있다.
상위 컴포넌트의 값이 변경되면 하위 컴포넌트에도 이 값이 자동으로 반영된다. 

예를 들어, 상위 컴포넌트인 App에서 하위 컴포넌트인 AppHeader로 title이라는 data를 넘겨준다고 하자.

App에서 정의한 title을 AppHeader에서 propsData라는 이름으로 받아 h1으로 출력해 주었다.

<!-- App component -->
<template>
  <div>
    <AppHeader :propsData="title"></AppHeader>
    <AppContent></AppContent>
  </div>
</template>

<script>
import AppHeader from './components/AppHeader.vue';
import AppContent from './components/AppContent.vue';

export default {
  data() {
    return {
      title: 'header title!'
    }
  },
  components: {
    AppHeader,
    AppContent,
  }
}
</script>
<!-- AppHeader component -->
<template>
  <div>
    <header>
      <h1>{{ propsData }}</h1>
    </header>
  </div>
</template>

<script>
export default {
  props: ['propsData']
}
</script>

그럼 아래와 같이 AppHeader에서 출력된 것을 확인할 수 있다.

App의 title data

또한, 데이터를 변경하면 바로 반영되는 것을 볼 수 있다.

App에서 title을 수정했을 때

 

 

반대로, 하위 컴포넌트에서 상위 컴포넌트로는 이벤트를 발생시킬 수 있다.

버튼을 누르면 숫자가 증가하는 예시를 들면, 

<!-- App -->
<template>
  <div>
    <AppHeader :props="title"></AppHeader>
    <AppContent @increaseNum="num+=1" :num="num"></AppContent>
  </div>
</template>

<script>
import AppHeader from './components/AppHeader.vue';
import AppContent from './components/AppContent.vue';

export default {
  data() {
    return {
      title: 'header title!',
      num: 0
    }
  },
  components: {
    AppHeader,
    AppContent,
  },
}
</script>
<!-- AppContent -->
<template>
  <div>
    <button @click="handleClick">{{ num }}</button>
  </div>
</template>

<script>
export default {
  props: ['num'],
  methods: {
    handleClick() {
      this.$emit('increaseNum');
    }
  }
}
</script>

 

아래에서 확인할 수 있는 것처럼 data는 App에 위치해 있지만,

버튼을 클릭하면, AppContent의 handleClick 이벤트가 일어나고 emit으로 상위의 increaseNum이라는 이벤트를 발생시킨다.
increaseNum은 App에 있는 num이라는 데이터 값을 1씩 증가시킨다. 이렇게 상위에서 변한 num이 하위에도 반영된 것을 확인할 수 있다.

 


양방향 데이터 바인딩

또한, Vue는 v-model을 통해 Angular처럼 양방향 데이터 바인딩을 제공한다. 

<!-- App -->
<template>
  <div>
    <input type="text" v-model="inputValue" />
    <p>inputValue: {{ inputValue }}</p>
</template>

<script>
export default {
  data() {
    return {
      inputValue: '',
    }
  },
}
</script>

input에 입력

input의 값을 입력해도 data의 값이 바뀌고

data를 직접 변경

직접 data의 값을 변경시켜도 input에 반영된다.

 

하지만 v-model을 사용할 때, 조심해야 할 점이 있다.

2023.06.01 - [Study] - [Vue.js] v-model 양방향 바인딩 문제 (feat. input event)

 

[Vue.js] v-model 양방향 바인딩 문제 (feat. input event)

v-model 양방향 바인딩 Vue.js의 경우에는 v-model을 통해 양방향 바인딩을 제공한다고 알고 있었다. Vue.js를 학습하며 토이 프로젝트를 진행 중, 영어의 경우에는 문제없이 입력값이 전부 잘 저장되지

ktmihs.tistory.com

위에서 따로 정리를 해두었는데, 결론적으로는 한국어는 v-model의 경우 바로바로 업데이트 되지 않는다는 것이다.

 

 

만약 이런 문자의 경우에도 실시간으로 데이터를 바인딩하고 싶다면 v-model 대신 input event listener를 사용하여 값을 가져와야 한다.

<template>
  <div>
    <input type="text" @input="e => inputValue = e.target.value" />
    <p>inputValue: {{ inputValue }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      inputValue: '',
    }
  }
}
</script>

한글의 경우에도 바로바로 값이 반영되는 것을 확인할 수 있다.

 


 

추가적으로, Vue는 React나 Angular 같은 다른 프론트엔드 프레임워크와 비교했을 때, 상대적으로 가볍고 빠르며, 문법이 단순하고 간결하여 초기 학습 비용이 낮은 덕분에 다른 프레임워크에 비해 진입장벽이 낮다는 장점이 있다.

React를 사용했던 입장에서 1, 2주 정도만 투자하면 무난하게 프로젝트를 진행할 수 있을 정도로 비슷한 개념도 많고 사용 방법이 명확했다.

 


 

REF

 

https://v2.ko.vuejs.org/v2/guide/index.html

https://ko.vuejs.org/guide/introduction.html

https://joshua1988.github.io/web-development/vuejs/vuejs-tutorial-for-beginner/

https://jminie.tistory.com/168

https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel

https://vuejs.org/guide/essentials/forms.html#text

728x90