본문 바로가기
Javascript/vue

vue3 데이터 반응성 (Reactivity) 이해하기

by SANCODE 2025. 5. 29.

Vue.js의 가장 큰 강점 중 하나는 바로 데이터 반응성(Reactivity)이다. 데이터가 바뀌면 자동으로 화면에 반영되는 이 기능 덕분에 개발자는 복잡한 DOM 조작 없이도 쉽고 빠르게 인터랙티브한 웹 애플리케이션을 만들 수 있다. 본 글에서는 Vue 데이터 반응성의 기본 개념과 작동 원리, 그리고 Vue 3에서 새롭게 추가된 Composition API를 중심으로 어떻게 반응형 데이터를 다루는지 쉽고 자세하게 설명고자 한다.

 

목차


    Vue 데이터 반응성 이해하기

    Vue.js에서 ‘데이터 반응성’이란, 데이터가 변경될 때 이를 자동으로 감지하여 화면에 즉시 반영하는 기능을 의미한다. 쉽게 말해, 우리가 화면에 보여주는 데이터가 변하면 개발자가 별도의 작업 없이도 UI가 자동으로 업데이트되는 것이다.



    왜 데이터 반응성이 중요할까?

    웹 애플리케이션은 사용자와 상호작용하며 데이터가 자주 바뀐다. 예를 들어 버튼을 눌러 카운터를 올리거나, 폼에 입력한 내용이 즉시 보이도록 해야 할 때가 있는데, 만약 개발자가 일일이 DOM 요소를 찾아서 업데이트한다면 너무 복잡하고 비효율적이다. Vue의 반응성 시스템은 이런 번거로움을 없애고, 데이터와 UI를 자연스럽게 연결해 준다.


    Vue 2와 Vue 3의 반응성 차이

    Vue 2: Vue는 Object.defineProperty를 사용해 객체의 속성 변화를 감지했으며, 이 방법은 대부분 잘 동작하지만, 배열이나 객체에 속성이 추가되거나 삭제될 때는 한계가 있다.
    Vue 3: 반응성 시스템을 Proxy 기반으로 완전히 새롭게 설계했으며, Proxy는 객체 전체를 감싸서 모든 변화를 감지할 수 있어, 더 유연하고 성능도 개선되었다.


    Vue 3 반응성 API 핵심 요소

    Vue 3에서는 데이터 반응성을 관리하기 위해 Composition API를 사용한다.

    reactive()
    객체 형태의 데이터를 반응형으로 만듭니다. 내부 속성 모두가 반응성을 가진다.

    ref()
    원시 값(숫자, 문자열 등)을 반응형으로 감쌀 때 사용하며, .value 프로퍼티로 실제 값에 접근한다.

    computed()
    반응형 데이터 기반으로 계산된 값을 만들 때 사용하며, 캐싱되어 효율적이다.

    watch()
    특정 데이터 변화를 감시하고, 변화가 생길 때마다 콜백 함수를 실행한다.


    예제

    <template>
      <div>
        <p>카운터: {{ count }}</p>
        <button @click="increment">증가</button>
      </div>
    </template>
    
    <script setup>
    import { ref } from 'vue'
    
    const count = ref(0)
    
    function increment() {
      count.value++
    }
    </script>


    <script setup>
    Vue 3에서 Composition API를 더 간결하게 쓰기 위한 문법이다.
    별도의 export default 없이 바로 변수를 선언하고 함수를 정의할 수 있다.

    import { ref } from 'vue'
    Vue가 제공하는 ref 함수를 가져온다.
    ref는 원시 값(숫자, 문자열 등)을 반응형 데이터로 만들어 주는 함수다.

    const count = ref(0)
    count 변수를 선언하는데, ref(0)으로 초기값 0을 가진 반응형 상태로 만든다.
    count는 실제 값에 접근하거나 변경할 때 .value를 사용해야 한다.

    function increment() { count.value++ }
    increment 함수는 count.value를 1씩 증가시키는 함수다.
    버튼 클릭 시 이 함수가 실행되어 count 값이 바뀌고, Vue가 이를 감지해 자동으로 화면을 업데이트한다.


    반응형


    Composition API를 쓰는 이유와 장점


    코드의 명확한 재사용과 로직 분리

    기존 Vue 2의 Options API는 컴포넌트 옵션(데이터, 메서드, 라이프사이클 등)을 카테고리별로 분리해서 작성한다.
    하지만 컴포넌트가 복잡해지면 서로 관련된 기능들이 데이터, 메서드, 라이프사이클 훅에 흩어져 있어 유지보수가 어렵고 재사용이 제한적이었다.


    Composition API는 기능별로 코드를 묶을 수 있다.
    예를 들어, 사용자 인증, API 호출, 폼 유효성 검사 등 로직 단위로 함수와 상태를 함께 묶어 분리할 수 있어 관련 로직을 한곳에서 관리하고 재사용하기 쉽다는 장점이 있다.

    function useCounter() {
      const count = ref(0)
      function increment() {
        count.value++
      }
      return { count, increment }
    }
    
    // 컴포넌트 안에서 사용
    const { count, increment } = useCounter()

    이처럼 함수로 캡슐화해 재사용 가능한 모듈로 만들기 편하다.


    타입스크립트 지원

    Composition API는 기본적으로 순수 함수와 변수로 구성되기 때문에, 타입스크립트와 궁합이 매우 좋다.
    Options API에서는 data, methods 등 여러 옵션에 나눠서 타입을 지정해야 했지만, Composition API에서는 일반 JS/TS 문법으로 상태와 함수를 선언하므로 정확하고 간결한 타입 정의가 가능하다.


    복잡한 컴포넌트 상태 관리 용이

    큰 규모의 컴포넌트는 상태가 복잡하고, 상태 간 의존성도 많다.
    Options API에서는 상태별로 선언이 분산되어 코드를 이해하기 어려워진다.
    Composition API는 상태와 관련 함수, 라이프사이클 훅을 한곳에 모아둬서, 컴포넌트의 상태 흐름을 쉽게 추적하고 관리할 수 있다.


    가독성과 유지보수 향상

    관련 로직을 한데 모아 관리하므로, 코드가 더 명확하고 직관적이다.
    특히 여러 명이 함께 작업할 때 역할 분담과 코드 파악이 쉬워져 협업에 도움이 된다.


    커스텀 훅 패턴 구현 가능

    React의 훅(Hooks)처럼 Composition API를 사용해 재사용 가능한 상태 관리 로직을 쉽게 만들 수 있다.
    예를 들어, useFetch, useForm, useAuth 같은 커스텀 훅을 작성해 여러 컴포넌트에서 공통 로직을 공유할 수 있다.



    반응성 한계와 주의점


    객체 속성 추가/삭제 감지 제한 (Vue 2 한계)

    Vue 2는 Object.defineProperty 기반으로 반응성을 구현해, 초기 객체에 존재하지 않는 속성 추가나 삭제를 자동으로 감지하지 못하는 한계가 있었다.
    특히 여러 명이 함께 작업할 때 역할 분담과 코드 파악이 쉬워져 협업에 도움이 된다.
    예를 들어, obj.newProp = 'value'를 해도 자동 업데이트가 되지 않으며, 해결책으로 Vue.set(obj, 'newProp', value)를 써야 한다.


    Vue 3 Proxy로 한계 개선

    Vue 3는 Proxy 기반 반응성 시스템을 도입해, 객체의 추가, 삭제, 접근, 설정 등 모든 변화를 감지할 수 있게 개선했다.
    그러나 Proxy도 완벽하지는 않아서, 비반응성 값이 포함되거나 Vue가 감지하지 못하는 경우가 존재한다.


    원시 값(Primitive) 반응성 주의

    ref()로 감싼 원시 값은 .value로 접근하고 변경해야 하며, ;">실수로 .value 없이 사용하면 반응성이 동작하지 않거나 의도치 않은 결과가 발생할 수 있다.
    템플릿 안에서는 Vue가 자동으로 언랩하지만, JS 코드 내에서는 항상 .value를 사용해야 한다.


    배열 조작과 반응성

    Vue 2에서는 배열의 직접 인덱스 변경(arr[0] = 'new')이 반응성을 트리거하지 않았고, 배열 길이 조절도 문제였다. Vue 3에서는 Proxy 덕분에 배열도 모든 변화를 감지하지만, 복잡한 배열 변형(예: splice, sort) 후 상태 관리에 주의가 필요하다.


    비반응성 데이터 포함 주의

    객체 내부에 비반응성(plain JS 객체, Date, Map, Set 등)을 포함할 경우, Vue 반응성 시스템이 이를 추적하지 못한다.
    예를 들어, reactive 객체 내부에 원시 JS 객체를 중첩하면 내부 변화가 감지되지 않을 수 있다. 이럴 땐 별도로 reactive 또는 ref로 감싸야 한다.



    마무리

    Vue.js의 데이터 반응성은 개발자가 UI와 데이터를 따로 신경 쓰지 않고도 자연스럽게 상태 변화를 처리할 수 있도록 돕는 핵심 기능이다. Vue 3에서 도입된 Proxy 기반의 반응성 시스템과 Composition API 덕분에 더 유연하고 효율적인 개발이 가능해졌다.

    이번 글에서는 기본 개념과 함께 Vue 3의 주요 반응성 API인 ref를 중심으로 살펴보았는데, 앞으로는 reactive, computed, watch 등 다양한 API를 활용해 보다 복잡하고 실용적인 애플리케이션 상태 관리를 구현할 수 있다.

    반응형