React에 익숙한 개발자가 Vue 3(Composition API, script setup)를 빠르게 읽을 수 있게 짝지어 본 표. 가장 큰 차이는 Vue는 반응성(Reactivity)을 자동으로 추적해서 의존성 배열(Dependency Array)이 없다는 점이다.
반응성
| React | Vue 3 | 메모 |
|---|---|---|
useState(0) | ref(0) | JS(JavaScript)에서는 x.value, 템플릿에서는 x |
| 객체 상태 | reactive(obj) | .value 없음. 구조분해하면 반응성이 끊긴다 |
useMemo | computed(() => ...) | 의존성 자동 추적 |
useCallback | 필요 없음 | 리렌더마다 함수를 다시 만드는 문제가 없다 |
useEffect(fn, [dep]) | watch(dep, fn) | 특정 값에 반응 |
| 자동 추적 Effect | watchEffect(fn) | 안에서 읽은 값에 반응 |
useEffect(fn, []) | onMounted(fn) | 정리는 onUnmounted나 watch의 onCleanup |
useRef | ref(null) + 템플릿 ref="el" | 상태와 DOM(Document Object Model) 참조를 겸한다 |
React는 상태가 바뀌면 컴포넌트 함수를 다시 실행하고 재조정(Reconciliation)으로 차이를 찾는다. 그래서 메모이제이션(Memoization)과 의존성 배열을 신경 써야 한다(React Compiler가 이 부담을 줄이는 중이다). Vue는 값을 읽은 곳을 기록해 두었다가 바뀐 곳만 다시 계산한다.
ref와 reactive
ref: 원시값이든 객체든 담는다. 어디서나.value, 통째로 재할당 가능. 실무에서는 대부분ref로 통일한다reactive: 객체·배열 전용. 변수 자체를 재할당하면 연결이 끊기고, 구조분해해도 끊긴다. 꺼내 쓰려면toRefs
컴포넌트
| React | Vue |
|---|---|
| props | defineProps |
onXxx 콜백 prop | defineEmits + emit('xxx', payload) |
children | slot(이름 붙인 slot으로 여러 구멍) |
onClick={fn} | @click="fn" |
cond && <X /> | v-if / v-show |
list.map() | v-for + :key |
className·style | :class·:style(객체·배열 바인딩) |
상태 공유
- Context →
provide/inject - Redux·Zustand → Pinia(공식 상태 관리). 스토어를 구조분해할 때 상태는
storeToRefs로 꺼낸다 → Redux 이후의 상태 관리 선택 - TanStack Query는 Vue용도 있어 서버 상태 패턴을 그대로 가져갈 수 있다
export const useCounter = defineStore('counter', () => {
const n = ref(0)
const double = computed(() => n.value * 2)
const inc = () => n.value++
return { n, double, inc }
})두 프레임워크 모두 상태에서 화면을 계산하는 선언형 UI이고, 반응성 모델이 다르다. Vue는 설계가 MVVM(Model-View-ViewModel) 패턴에서 일부 영감을 받았다고 Vue 2 공식 가이드에서 밝혔다. 템플릿 대신 컴파일러에 더 기대는 쪽은 Svelte.