반응형 데이터 처리

VUE.JS BASIC
Chapter 5. 반응형 데이터 처리
ref(), reactive(), computed(), watch()를 이용해
데이터 변화에 자동으로 반응하는 Vue 프로그램을 만들어 봅니다.
노트북으로 웹 프로그래밍을 공부하는 모습
Vue의 핵심은 데이터가 변경되면 연결된 화면도 자동으로 반응한다는 점입니다.
5.1 반응형 데이터란?

지금까지 Vue를 공부하면서 다음과 같은 문법을 사용했습니다.

1 지금까지 배운 Vue 문법
  • ref() — 데이터 관리
  • {{ }} — 화면 출력
  • @click — 이벤트 처리
  • v-model — 입력값 연결
  • v-if — 조건 처리
  • v-for — 반복 처리

이번 장에서는 Vue의 핵심 개념인 반응형 데이터(Reactive Data)를 조금 더 자세히 살펴봅니다.

💡 반응형 데이터란?

데이터가 변경되었을 때 그 데이터를 사용하는 화면도 자동으로 변경되는 데이터를 말합니다.

데이터 변경

Vue가 변경 감지

관련된 화면 자동 갱신
대표적인 반응형 기능
기능 역할
ref() 하나의 값이나 데이터를 반응형으로 관리
reactive() 객체를 반응형으로 관리
computed() 기존 데이터를 이용하여 새로운 값을 계산
watch() 특정 데이터의 변경을 감지하여 작업 실행
5.2 ref() 다시 이해하기

ref()는 지금까지 계속 사용했던 가장 기본적인 Vue 반응형 기능입니다.

Vue - ref() 기본 사용법
<script setup>
import { ref } from 'vue'

const count = ref(100)
</script>

<template>
  <h2>현재 값 : {{ count }}</h2>
</template>

JavaScript 영역에서 ref로 만든 값을 변경할 때는 .value를 사용합니다.

JavaScript
count.value = 200

값이 변경되면 화면에서 사용하고 있는 {{ count }}도 자동으로 변경됩니다.

count = 100

count.value = 200

화면의 {{ count }}도 200으로 자동 변경
💡 기억하세요

script 영역에서는 count.value를 사용하지만, template 영역에서는 일반적으로 {{ count }}처럼 사용합니다.

5.3 ref()로 문자열 관리하기

ref()는 숫자뿐 아니라 문자열도 반응형 데이터로 관리할 수 있습니다.

Vue - 문자열 변경
<script setup>
import { ref } from 'vue'

const name = ref('홍길동')

function changeName() {
  name.value = '김철수'
}
</script>

<template>
  <h2>사원 이름</h2>

  <p>{{ name }}</p>

  <button @click="changeName">
    이름 변경
  </button>
</template>
버튼을 누르기 전
홍길동
이름 변경 버튼을 누른 후
김철수
홍길동 → name.value 변경 → 김철수
5.4 reactive()

실제 프로그램에서는 사원처럼 서로 관련된 여러 데이터를 하나의 묶음으로 관리해야 하는 경우가 많습니다.

ref()를 이용하면 다음과 같이 각각 만들 수 있습니다.

JavaScript - ref() 사용
const name = ref('홍길동')
const age = ref(30)
const phone = ref('010-1111-2222')
const department = ref('개발팀')

물론 이렇게 작성해도 되지만, 모두 한 명의 사원에 대한 정보라면 하나의 객체로 묶는 것이 관리하기 편리합니다.

JavaScript - reactive() 사용
const employee = reactive({
  name: '홍길동',
  age: 30,
  phone: '010-1111-2222',
  department: '개발팀'
})
💡 reactive()의 역할

여러 속성을 가진 객체를 하나의 반응형 데이터로 관리할 때 편리하게 사용할 수 있습니다.

코드를 작성하고 있는 웹 개발 환경
여러 데이터를 하나의 객체로 구성하면 실제 프로그램의 데이터 구조를 더 쉽게 관리할 수 있습니다.
5.5 reactive() 기본 사용법
Vue - reactive() 기본 예제
<script setup>
import { reactive } from 'vue'

const employee = reactive({
  name: '홍길동',
  age: 30,
  department: '개발팀'
})
</script>

<template>
  <h2>사원정보</h2>

  <p>이름 : {{ employee.name }}</p>
  <p>나이 : {{ employee.age }}</p>
  <p>부서 : {{ employee.department }}</p>
</template>
실행 결과
사원정보
이름 : 홍길동
나이 : 30
부서 : 개발팀

객체의 값을 변경할 때는 속성을 직접 변경합니다.

JavaScript
employee.name = '김철수'
employee.age = 35
employee.department = '영업팀'
⚠ ref()와 다른 점

reactive()로 만든 객체의 속성을 변경할 때는 ref()처럼 .value를 사용하지 않습니다.

비교
name.value = '김철수'       // ref()

employee.name = '김철수'    // reactive()
5.6 ref와 reactive 비교
ref()
JavaScript
const name = ref('홍길동')

name.value = '김철수'
reactive()
JavaScript
const employee = reactive({
  name: '홍길동',
  age: 30
})

employee.name = '김철수'
구분 ref() reactive()
주 사용 형태 단일 값부터 객체까지 객체 / 배열
값 변경 .value 사용 속성 직접 변경
count.value = 100 employee.name = '홍길동'
초보자 활용 매우 많음 객체 관리에 편리
하나의 값
count / name / price
→ ref()

여러 속성을 가진 하나의 객체
employee / member / product
→ reactive()
💡 꼭 알아둘 점

ref()도 객체와 배열을 저장할 수 있으며, 실제 Vue 개발에서도 매우 많이 사용합니다.

5.7 reactive()와 v-model 연결

reactive()로 만든 객체의 속성도 v-model과 직접 연결할 수 있습니다.

Vue - 사원 등록
<script setup>
import { reactive } from 'vue'

const employee = reactive({
  name: '',
  phone: '',
  department: '개발팀'
})
</script>

<template>
  <h2>사원 등록</h2>

  <p>
    이름 :
    <input v-model="employee.name">
  </p>

  <p>
    전화번호 :
    <input v-model="employee.phone">
  </p>

  <p>
    부서 :
    <select v-model="employee.department">
      <option>개발팀</option>
      <option>영업팀</option>
      <option>관리팀</option>
    </select>
  </p>

  <hr>

  <p>이름 : {{ employee.name }}</p>
  <p>전화번호 : {{ employee.phone }}</p>
  <p>부서 : {{ employee.department }}</p>
</template>

여러 변수를 각각 만드는 대신 하나의 employee 객체 안에서 관련 데이터를 함께 관리할 수 있습니다.

employee

├─ name
├─ phone
└─ department
5.8 computed()

웹 프로그램에서는 이미 존재하는 데이터를 이용하여 새로운 값을 계산해야 하는 경우가 많습니다.

상품 주문 예
상품 가격 : 10,000원
수량 : 3개

총 금액 : 30,000원

총 금액은 독립적인 데이터라기보다 가격 × 수량으로 계산할 수 있는 값입니다.

💡 이런 경우 computed()

다른 반응형 데이터를 이용해 계산된 결과가 필요하다면 computed()를 사용할 수 있습니다.

5.9 computed() 기본 사용법
Vue - computed() 기본 예제
<script setup>
import { ref, computed } from 'vue'

const price = ref(10000)
const count = ref(2)

const total = computed(() => {
  return price.value * count.value
})
</script>

<template>
  <h2>상품 주문</h2>

  <p>가격 : {{ price }}원</p>
  <p>수량 : {{ count }}개</p>
  <p>총 금액 : {{ total }}원</p>
</template>
현재 실행 결과
가격 : 10000원
수량 : 2개
총 금액 : 20000원

수량을 3으로 변경해 봅니다.

JavaScript
count.value = 3
count = 2 → total = 20,000
count = 3 → total = 30,000

count가 변경되면 Vue가 이를 감지하고 total을 자동으로 다시 계산합니다.

5.10 실습 — 주문 수량 계산기
🧪 실습 목표
수량을 증가하거나 감소시켰을 때 computed()가 총 금액을 자동으로 다시 계산하는 과정을 확인합니다.
Vue - 주문 수량 계산기
<script setup>
import { ref, computed } from 'vue'

const productName = ref('노트북')
const price = ref(1200000)
const count = ref(1)

const total = computed(() => {
  return price.value * count.value
})

function increase() {
  count.value++
}

function decrease() {
  if (count.value > 1) {
    count.value--
  }
}
</script>

<template>
  <h1>상품 주문</h1>

  <p>상품명 : {{ productName }}</p>

  <p>
    가격 :
    {{ price.toLocaleString() }}원
  </p>

  <p>
    수량 :
    {{ count }}개
  </p>

  <button @click="decrease">
    -
  </button>

  <button @click="increase">
    +
  </button>

  <hr>

  <h2>
    총 금액 :
    {{ total.toLocaleString() }}원
  </h2>
</template>
처음 화면
상품명 : 노트북
가격 : 1,200,000원
수량 : 1개
[-] [+]
총 금액 : 1,200,000원
+ 버튼을 한 번 누르면
수량 : 2개
총 금액 : 2,400,000원
+ 버튼을 다시 누르면
수량 : 3개
총 금액 : 3,600,000원
count 변경

computed() 재계산

total 변경

화면 자동 갱신
5.11 computed()를 사용하는 이유

computed()를 사용하지 않고 계산 결과를 ref()로 관리할 수도 있습니다.

직접 계산하는 방식
const total = ref(0)

function calculate() {
  total.value = price.value * count.value
}

하지만 이 방식에서는 가격이나 수량이 변경될 때마다 calculate()를 직접 호출해야 합니다.

computed() 사용
const total = computed(() => {
  return price.value * count.value
})
직접 관리
price 변경 ──→ calculate()
count 변경 ──→ calculate()

computed 사용
price ──┐
├──→ total 자동 계산
count ──┘
💡 computed()의 장점

Vue가 계산에 사용되는 반응형 데이터를 추적하므로 계산 결과를 별도로 계속 관리할 필요가 줄어듭니다.

5.12 여러 데이터 계산하기

computed()는 단순한 곱셈뿐 아니라 배열 데이터를 이용한 인원수 계산에도 사용할 수 있습니다.

Vue - 사원 현황 계산
<script setup>
import { ref, computed } from 'vue'

const employees = ref([
  { id: 1, name: '홍길동', department: '개발팀' },
  { id: 2, name: '김철수', department: '영업팀' },
  { id: 3, name: '이영희', department: '개발팀' }
])

const employeeCount = computed(() => {
  return employees.value.length
})

const developerCount = computed(() => {
  return employees.value.filter(
    emp => emp.department === '개발팀'
  ).length
})
</script>

<template>
  <h2>사원 현황</h2>

  <p>
    전체 사원 : {{ employeeCount }}명
  </p>

  <p>
    개발팀 : {{ developerCount }}명
  </p>
</template>
실행 결과
전체 사원 : 3명
개발팀 : 2명

employees 배열에 사원을 추가하거나 삭제하면 계산 결과도 자동으로 변경됩니다.

프로그래밍 소스 코드가 표시된 개발 화면
computed와 watch를 활용하면 데이터 사이의 관계와 변경 흐름을 더욱 명확하게 구성할 수 있습니다.
5.13 watch()

computed()는 기존 데이터를 이용해 새로운 값을 계산할 때 사용합니다.

반면 watch()는 특정 데이터가 변경되었을 때 어떤 작업을 실행하고 싶을 때 사용합니다.

Vue - 검색어 변경 감지
<script setup>
import { ref, watch } from 'vue'

const keyword = ref('')

watch(keyword, (newValue, oldValue) => {
  console.log('이전 값 :', oldValue)
  console.log('새로운 값 :', newValue)
})
</script>

<template>
  <h2>사원 검색</h2>

  <input
    v-model="keyword"
    placeholder="이름 검색"
  >

  <p>
    검색어 : {{ keyword }}
  </p>
</template>

사용자가 입력창에 을 입력하면 keyword 값이 변경되고, watch()가 이 변화를 감지합니다.

keyword 변경

watch() 감지

지정된 함수 실행
5.14 watch() 활용 예

수량이 10개를 초과하면 경고 메시지를 표시하는 예제를 만들어 보겠습니다.

Vue - 수량 변경 감지
<script setup>
import { ref, watch } from 'vue'

const count = ref(1)

watch(count, (newCount) => {
  if (newCount > 10) {
    alert('10개를 초과했습니다.')
  }
})

function increase() {
  count.value++
}
</script>

<template>
  <h2>수량 : {{ count }}</h2>

  <button @click="increase">
    증가
  </button>
</template>
count 변경

watch() 실행

조건 확인

필요한 작업 실행
💡 watch()는 언제 사용할까?

특정 값이 변경되었을 때 로그 기록, 경고 표시, 추가적인 처리 등을 실행해야 할 때 활용할 수 있습니다.

5.15 computed와 watch 차이

처음 Vue를 배우면 computed()와 watch()가 비슷해 보일 수 있습니다. 다음과 같이 역할을 구분하면 이해하기 쉽습니다.

기능 목적
computed() 새로운 값 계산 총 금액, 인원수
watch() 변경 감지 후 작업 실행 로그, 경고, 추가 처리
computed()
가격 × 수량 = 총 금액
→ computed()
watch()
수량 변경

10개 초과인지 확인

경고창 표시
→ watch()
💡 이렇게 질문하면 구분하기 쉽습니다

computed() → "결과값이 무엇인가?"

watch() → "값이 바뀌었을 때 무엇을 할 것인가?"

5.16 실습 — 상품 주문 관리 프로그램
🧪 종합 실습
지금까지 배운 ref(), reactive(), computed(), watch()를 하나의 프로그램에서 함께 사용해 봅니다.
Vue - 상품 주문 관리
<script setup>
import {
  ref,
  reactive,
  computed,
  watch
} from 'vue'

const product = reactive({
  name: '노트북',
  price: 1200000
})

const count = ref(1)

const total = computed(() => {
  return product.price * count.value
})

function increase() {
  count.value++
}

function decrease() {
  if (count.value > 1) {
    count.value--
  }
}

watch(count, (newCount) => {
  if (newCount >= 5) {
    console.log('대량 주문입니다.')
  }
})
</script>

<template>
  <h1>상품 주문 관리</h1>

  <p>
    상품명 : {{ product.name }}
  </p>

  <p>
    가격 :
    {{ product.price.toLocaleString() }}원
  </p>

  <p>
    수량 : {{ count }}개
  </p>

  <button @click="decrease">
    감소
  </button>

  <button @click="increase">
    증가
  </button>

  <hr>

  <h2>
    총 금액 :
    {{ total.toLocaleString() }}원
  </h2>
</template>
각 기능의 역할
1 reactive()
상품명과 가격을 하나의 product 객체로 관리합니다.
2 ref()
주문 수량 count를 반응형 데이터로 관리합니다.
3 computed()
상품 가격과 수량을 이용해 총 금액을 자동으로 계산합니다.
4 watch()
수량의 변경을 감지하여 5개 이상이면 메시지를 출력합니다.
product.price ────────┐
├──→ computed() → total → 화면
count ────────────────┘

├──→ 화면
└──→ watch() → 변경 감지
💡 Vue의 데이터 흐름

데이터 사이의 관계를 만들어 두면 데이터가 변경될 때 필요한 계산 결과와 화면이 자동으로 반응합니다.

5.17 실습 — 사원정보 수정

마지막으로 reactive()를 실제 사원관리 프로그램과 비슷한 형태로 사용해 봅니다.

Vue - 사원정보 수정
<script setup>
import { reactive } from 'vue'

const employee = reactive({
  name: '홍길동',
  phone: '010-1111-2222',
  department: '개발팀'
})

function changeEmployee() {
  employee.name = '김철수'
  employee.phone = '010-3333-4444'
  employee.department = '영업팀'
}

function clearEmployee() {
  employee.name = ''
  employee.phone = ''
  employee.department = ''
}
</script>

<template>
  <h1>사원정보</h1>

  <p>
    이름 :
    <input v-model="employee.name">
  </p>

  <p>
    전화번호 :
    <input v-model="employee.phone">
  </p>

  <p>
    부서 :
    <input v-model="employee.department">
  </p>

  <button @click="changeEmployee">
    정보 변경
  </button>

  <button @click="clearEmployee">
    초기화
  </button>

  <hr>

  <h2>현재 정보</h2>

  <p>이름 : {{ employee.name }}</p>
  <p>전화번호 : {{ employee.phone }}</p>
  <p>부서 : {{ employee.department }}</p>
</template>

정보 변경 버튼을 누르면 changeEmployee() 함수에서 employee 객체의 속성을 변경합니다.

핵심 코드
employee.name = '김철수'
employee.phone = '010-3333-4444'
employee.department = '영업팀'
정보 변경 후
이름 : 김철수
전화번호 : 010-3333-4444
부서 : 영업팀

데이터가 변경되면 v-model로 연결된 입력창과 {{ }}로 출력하는 현재 정보 영역이 함께 자동으로 변경됩니다.

employee 데이터 변경

Vue가 변경 감지

입력창 자동 변경
+
출력 화면 자동 변경
💡 데이터 중심으로 생각하기

Vue에서는 화면의 HTML을 직접 찾아 수정하는 대신 데이터를 변경합니다.

그러면 Vue가 그 데이터를 사용하는 화면을 자동으로 갱신합니다. 이것이 Vue에서 데이터를 중심으로 프로그램을 관리하는 기본 방식입니다.

📌 Chapter 5 핵심 정리
  • 반응형 데이터는 데이터가 변경될 때 연결된 화면도 자동으로 변경되는 데이터입니다.
  • ref()는 숫자, 문자열 등 다양한 데이터를 반응형으로 관리할 수 있습니다.
  • script 영역에서 ref()의 값을 변경할 때는 .value를 사용합니다.
  • reactive()는 여러 속성을 가진 객체를 하나의 반응형 데이터로 관리할 때 편리합니다.
  • reactive() 객체의 속성을 변경할 때는 .value를 사용하지 않고 속성을 직접 변경합니다.
  • reactive() 객체의 속성도 v-model과 연결할 수 있습니다.
  • computed()는 기존 반응형 데이터를 이용하여 새로운 값을 계산할 때 사용합니다.
  • computed()가 사용하는 데이터가 변경되면 계산 결과도 자동으로 다시 계산됩니다.
  • watch()는 특정 데이터의 변경을 감지한 뒤 필요한 작업을 실행할 때 사용합니다.
  • computed()는 "결과값이 무엇인가?", watch()는 "값이 바뀌었을 때 무엇을 할 것인가?"로 구분하면 이해하기 쉽습니다.
  • Vue에서는 화면을 직접 수정하기보다 데이터를 관리하고 데이터 사이의 관계를 만드는 방식으로 프로그램을 구성합니다.

프로그램·홈페이지·강의가 필요하신가요?

프로그램 판매, 무료 다운로드, 홈페이지 제작, IT 강의 상담을 도와드립니다.

상담 신청하기