Vue Composition API: Computed와 Ref 프로퍼티 설명

발행: (2026년 2월 20일 오전 05:44 GMT+9)
11 분 소요
원문: Dev.to

I’m happy to translate the article for you, but I’ll need the full text of the post (the paragraphs you’d like translated). Could you please paste the content you want translated here? I’ll keep the source link at the top and preserve all formatting, code blocks, URLs, and technical terms as requested.

1️⃣ State – the foundation

State는 단순히 시간이 지나면서 변할 수 있는 데이터이며, 사용자가 화면에서 보는 내용에 영향을 줍니다.
데이터가 변하고 그 때문에 UI가 업데이트되어야 한다면, 그 데이터가 state입니다.

프론트엔드 애플리케이션에서 state의 예시:

  • 카운터 값
  • API에서 가져온 사용자 목록
  • 모달이 열려 있는지 여부
  • 입력 필드의 내용
  • 현재 로그인한 사용자

백엔드 배경을 가지고 있다면 이미 state에 익숙합니다: 데이터베이스 레코드, 요청/응답 객체, 세션 데이터, 캐시된 값… 차이점은 그 위치입니다.

Traditional backend‑driven flow

  1. 클라이언트가 요청을 보냅니다.
  2. 서버가 데이터를 처리합니다.
  3. 서버가 HTML 또는 JSON을 반환합니다.
  4. 페이지가 새 데이터와 함께 다시 로드됩니다.

이 모델에서는 대부분의 state가 서버에 존재합니다.

Modern frontend flow (Vue)

  • State는 브라우저 안에 존재합니다.
  • 전체 페이지를 다시 로드하지 않습니다.
  • 사용자가 버튼을 클릭 → 메모리 내 데이터가 변함 → UI가 자동으로 업데이트됩니다.

그 자동 업데이트를 reactivity라고 부릅니다. Vue는 어떤 데이터가 UI 업데이트를 트리거해야 하는지 알 필요가 있는데, 바로 refcomputed가 제공하는 기능입니다.

2️⃣ ref – 반응형 상태

ref는 Vue가 감시하는 반응형 값(숫자, 문자열, 불리언 등)을 생성합니다. 값이 변경되면 Vue가 자동으로 UI를 업데이트합니다.

기본 예시 (Vue 3 + TypeScript)

import { ref } from 'vue'

const count = ref(0)

function increment() {
  count.value++
}
  • ref(0)은 TypeScript에게 이 ref가 숫자를 포함하고 있음을 알려줍니다.
  • 실제 값은 .value를 통해 접근합니다.
  • count.value가 변경되면 Vue는 의존하는 UI를 다시 렌더링합니다.

템플릿에서 사용하기

{{ count }}

<button @click="increment">Increment</button>

템플릿에서는 Vue가 ref를 자동으로 언래핑하기 때문에 .value를 사용할 필요가 없습니다.

객체와 함께 사용하는 ref

객체(특히 TypeScript 인터페이스)를 다룰 때도 ref를 사용할 수 있습니다.

interface User {
  name: string
  age: number
}

const user = ref({
  name: 'Lou',
  age: 27
})

// 속성 업데이트
user.value.age++

주로 객체를 다룬다면 reactive 함수를 접하게 되겠지만, 핵심 아이디어는 동일합니다: Vue는 변경을 추적하고 상태가 변하면 UI를 업데이트합니다.

3️⃣ computed – 파생(읽기‑전용) 상태

ref진실의 원천이라면, computed그 원천으로부터 파생된 값을 나타냅니다. 파생된 상태는 다른 상태로부터 계산되며 항상 동기화돼야 하고, 수동으로 업데이트해서는 안 됩니다.

간단한 파생 상태 예시

import { ref, computed } from 'vue'

const price = ref(10)
const quantity = ref(2)

const total = computed(() => {
  return price.value * quantity.value
})
  • pricequantity는 원천 상태(ref)입니다.
  • total은 파생 상태(computed)입니다.

백엔드 관점에서 보면, 이는 계산된 컬럼이나 다른 필드로부터 만들어진 DTO 필드와 비슷합니다. price * quantity 로 언제든지 계산할 수 있기 때문에 total을 데이터베이스에 별도로 저장하지 않습니다. 그렇게 하면 중복과 일관성 문제가 발생할 수 있습니다. computed는 클라이언트 측에서 동일한 역할을 수행합니다.

computed와 일반 함수 비교

function fullName() {
  return `${firstName.value} ${lastName.value}`
}
{{ fullName() }}

computed를 선호할까?

일반 함수computed
매 렌더링마다 실행✅ (항상)❌ (의존성이 변할 때만)
캐싱없음있음 (캐시됨)
의존성 추적수동자동

일반 함수는 컴포넌트가 다시 렌더링될 때마다 실행됩니다. 반면 computed 속성은 캐시되어, Vue가 어떤 반응형 값에 의존하는지 추적하고 해당 값이 변할 때만 다시 계산합니다. 계산 비용이 큰 경우, computed를 사용하면 코드가 더 효율적이고 이해하기 쉬워집니다.

판단 기준

이 값이 진실의 원천인가, 아니면 다른 것으로부터 파생된 것인가?

  • 진실의 원천ref 사용.
  • 파생된 값computed 사용.

이 사고 모델은 데이터 일관성과 단일 진실 원천을 중시하는 백엔드 사고 방식과 잘 맞습니다.

getter와 setter가 있는 computed

때때로 읽기와 쓰기 모두 가능한 computed 속성이 필요할 수 있습니다. 이때는 getter와 setter를 함께 제공하면 됩니다:

import { ref, computed } from 'vue'

const firstName = ref('John')
const lastName = ref('Doe')

const fullName = computed({
  get() {
    return `${firstName.value} ${lastName.value}`
  },
  set(value: string) {
    const [first, ...rest] = value.split(' ')
    firstName.value = first
    lastName.value = rest.join(' ')
  }
})

이제 fullName을 일반 반응형 속성처럼 사용할 수 있습니다:

First name: {{ firstName }}

Last name: {{ lastName }}

사용자가 입력을 수정하면 setter가 firstNamelastName을 적절히 업데이트하고, UI는 자동으로 동기화됩니다.

4️⃣ 요약

ConceptPurposeTypical use
ref반응형 원시값 또는 객체 상태 생성카운터, 토글, API 응답
computed다른 ref를 기반으로 파생된, 캐시된 상태 정의계산된 합계, 포맷된 문자열, 필터링된 리스트
reactive (not covered in depth)깊이 반응형 객체 만들기 (ref를 대체하는 객체용)복잡한 중첩 상태

Remember:

  • ref = 진실의 원천 (변경 가능).
  • computed = 파생된, 읽기 전용 (setter를 추가하지 않는 한).

이 두 빌딩 블록을 이해하면 백엔드 배경에 관계없이 Vue 3의 반응성 시스템에 바로 익숙해질 수 있습니다.

코딩 즐기세요! 🚀

Vue 3 + TypeScript에서 refcomputed 사용하기

watch(() => fullName.value, (value) => {
  const parts = value.split(' ')
  firstName.value = parts[0]
  lastName.value = parts[1]
})

이제 값을 직접 할당할 수 있습니다:

fullName.value = 'Lou Creemers'

하나의 입력 필드가 여러 상태를 나타내는 폼에서 유용합니다.

Vue 3 + TypeScript의 타입

Vue 3를 TypeScript와 함께 사용할 때는 타입을 일찍 생각해 두는 것이 좋습니다.
TypeScript는 종종 타입을 자동으로 추론할 수 있습니다:

const isVisible = ref(true) // inferred as Ref<boolean>

같은 문법으로 명시적으로 정의할 수도 있습니다:

const isVisible = ref(true)

computed의 경우 반환 타입이 보통 추론됩니다. 필요하다면 직접 정의할 수 있습니다:

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

타입을 명확히 하면 특히 큰 프로젝트나 팀 환경에서 미묘한 버그를 예방하는 데 도움이 됩니다.

일반적인 실수

  • 스크립트 내부에서 .value 사용을 잊는 경우.
  • setter를 정의하지 않고 computed 속성을 변경하려는 경우.
  • 일반 상수로 사용해야 할 것을 computed로 사용하는 경우.

템플릿에서 무언가가 업데이트되지 않는다면, 가장 먼저 확인해야 할 것은 실제로 reactive source를 사용하고 있는지 여부입니다.

refcomputed가 중요한가

refcomputed는 Vue 3의 반응성 모델의 핵심 요소입니다.
소스 상태(ref)와 파생 상태(computed)의 차이를 이해하면 컴포넌트를 훨씬 더 쉽게 파악할 수 있습니다.

Vue 3와 TypeScript로 애플리케이션을 구축한다면, 이 두 개념을 마스터하는 것이 이후 모든 것에 대한 강력한 기반이 됩니다.

질문이 있나요?

언제든지 연락 주세요: louella.dev/socials 또는 아래에 댓글을 남겨 주세요.

다음에 또 봐요!

0 조회
Back to Blog

관련 글

더 보기 »

AI Gateway에서 Veo 비디오 모델

Google의 Veo 모델을 사용하여 동기화된 오디오가 포함된 포토리얼리스틱 비디오를 생성하세요. 이제 AI Gateway를 통해 이용할 수 있습니다. AI SDK V6를 통해 사용해 보거나 선택하여 체험해 보세요.