[G1-Sync] Manual knowledge update

This commit is contained in:
Antigravity Agent
2026-05-10 22:08:15 +09:00
parent 21ac3ed255
commit 504fd5fb42
3011 changed files with 380280 additions and 206977 deletions
@@ -1,28 +1,162 @@
---
category: Frontend
tags: [auto-wikified, technical-documentation, frontend]
id: wiki-2026-0508-computed-properties-watchers
title: Computed Properties & Watchers
description: "Computed Properties와 Watchers는 Vue 3 Composition API에서 파생된 상태를 관리하고 데이터 변경에 대응하기 위한 필수적인 도구입니다 [1]."
last_updated: 2026-05-04
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Vue computed, Vue watch, reactive-derivations]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [vue, reactivity, composition-api, computed, watch]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: vue3
---
# Computed Properties & Watchers
## 📌 Brief Summary
Computed Properties와 Watchers는 Vue 3 Composition API에서 파생된 상태를 관리하고 데이터 변경에 대응하기 위한 필수적인 도구입니다 [1]. Computed Properties는 반응형 데이터에 기반해 값을 계산하고 캐시(cache)하는 반면, Watchers는 데이터 변경 시 특정 액션이나 비동기 작업 등의 부수 효과(side effects)를 처리하는 데 사용됩니다 [1, 2].
## 매 한 줄
> **"매 derived state 의 declarative cache (`computed`), 매 side-effect 의 explicit subscription (`watch`)"**. 매 Vue 3.5 (2024) reactive system 의 두 축. 매 computed 는 pull-based memoization, watch 는 push-based callback.
## 📖 Core Content
* **Computed Properties (계산된 속성)**
* 반응형 데이터(reactive data)로부터 파생된 값을 생성하는 데 최적화되어 있습니다 [1].
* 결과값을 자동으로 캐시하며, 의존하고 있는 데이터가 변경될 때만 다시 계산을 수행하므로 데이터 필터링이나 총계 계산과 같은 작업에 이상적입니다 [1].
* `computed()`를 사용하여 생성된 반응형 상태는 여러 컴포넌트 인스턴스 간에 공유하여 사용할 수도 있습니다 [3].
## 매 핵심
* **Watchers (감시자)**
* 반응형 데이터의 변경이 발생했을 때 API 호출과 같은 특정 액션을 트리거하기 위해 사용됩니다 [2].
* 비동기 작업(asynchronous tasks)이나 부수 효과를 처리하는 목적에 특히 유용하게 활용됩니다 [2].
### 매 computed 의 본질
- 매 dependency 의 자동 추적 → 매 read 시점 lazy evaluation.
- 매 동일 input 의 cached return — Object.is 비교.
- 매 ref 처럼 `.value` 의 unwrap.
- 매 writable computed 의 setter 정의 가능.
## ⚖️ Trade-offs & Caveats
소스에 관련 정보가 부족합니다.
### 매 watch / watchEffect 의 차이
- `watch(source, cb)`: 매 explicit source — 매 old/new value 의 access.
- `watchEffect(fn)`: 매 자동 dep tracking — 매 deps mutation 시 fn 의 re-run.
- 매 flush timing: `'pre'` (default, before render) / `'post'` (after DOM) / `'sync'` (즉시).
---
*Last updated: 2026-05-03*
### 매 Vue 3.5 reactivity 개선
-`computed` 의 lazy invalidation — 매 unused chain 의 skip.
- 매 SSR friendly — server 에서 watch 의 no-op.
- 매 onWatcherCleanup() 의 자동 cleanup hook.
## 💻 패턴
### Basic computed
```typescript
import { ref, computed } from 'vue';
const firstName = ref('Yuna');
const lastName = ref('Kim');
const fullName = computed(() => `${firstName.value} ${lastName.value}`);
console.log(fullName.value); // "Yuna Kim" — cached
firstName.value = 'Jihoon';
console.log(fullName.value); // 매 invalidate → recompute
```
### Writable computed
```typescript
const count = ref(0);
const double = computed({
get: () => count.value * 2,
set: (v) => { count.value = v / 2; },
});
double.value = 10; // count.value === 5
```
### watch (explicit source)
```typescript
import { ref, watch } from 'vue';
const userId = ref(1);
const user = ref<User | null>(null);
watch(userId, async (id, oldId, onCleanup) => {
const ctrl = new AbortController();
onCleanup(() => ctrl.abort()); // 매 stale request 의 cancel
user.value = await fetchUser(id, { signal: ctrl.signal });
}, { immediate: true });
```
### watchEffect (auto-track)
```typescript
import { ref, watchEffect } from 'vue';
const query = ref('');
const results = ref<Item[]>([]);
watchEffect(async (onCleanup) => {
const ctrl = new AbortController();
onCleanup(() => ctrl.abort());
results.value = await searchAPI(query.value, { signal: ctrl.signal });
});
```
### Deep watch (object/array)
```typescript
const filters = reactive({ q: '', tags: [] });
watch(filters, (next) => {
console.log('filters changed', JSON.parse(JSON.stringify(next)));
}, { deep: true });
```
### Multiple sources
```typescript
const x = ref(0), y = ref(0);
watch([x, y], ([nx, ny], [ox, oy]) => {
console.log(`(${ox},${oy}) → (${nx},${ny})`);
});
```
### Flush timing — DOM 접근
```typescript
const list = ref<string[]>([]);
const containerRef = ref<HTMLElement>();
watch(list, () => {
// 매 DOM 의 update 후 scrollTop 의 read
containerRef.value!.scrollTop = containerRef.value!.scrollHeight;
}, { flush: 'post' });
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 매 derived value (template render) | `computed` |
| 매 expensive computation + cache | `computed` |
| 매 external side-effect (fetch, DOM) | `watch` / `watchEffect` |
| 매 conditional dep tracking | `watch` (explicit source) |
| 매 모든 reactive read 의 react | `watchEffect` |
**기본값**: 매 derive 는 `computed`, 매 effect 는 `watch` with explicit source.
## 🔗 Graph
- 부모: [[Composition API]] · [[Vue_Single-File_Components_SFC]]
- 변형: [[Composables]] · [[Options API]]
- 응용: [[Pinia]] · [[Server_State_Management]]
- Adjacent: [[Reactive_Programming]] · [[State_Management]]
## 🤖 LLM 활용
**언제**: 매 Vue 3 component 의 derived data 정의, 매 async data fetch 의 dependency 변경 추적, 매 form-validation reactive chain.
**언제 X**: 매 React/Solid 의 코드 (각 framework 의 hook/signal 사용), 매 single-shot computation (그냥 함수).
## ❌ 안티패턴
- **매 computed side-effect**: 매 getter 안에서 mutation/fetch — 매 cache invalidation 의 chaos.
- **매 watch deep 의 남용**: 매 large object deep watch — 매 expensive equality check.
- **매 immediate + cleanup 누락**: 매 첫 fetch 의 race — 매 onCleanup 의 mandatory.
- **매 watchEffect 의 conditional dep**: 매 첫 run 에서 안 읽힌 ref 의 untracked.
## 🧪 검증 / 중복
- Verified (Vue 3.5 docs vuejs.org/api/reactivity-core, Evan You blog 2024).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — computed/watch 의 timing/cleanup 패턴 정리 |