vue를 새로 하게 되었다. 회사에서 React 대신 Vue를 쓰고 있어서다. 뉴비의 관점에서 배운 것들을 정리해봤다.
ref vs. reactive
ref, reactive 모두 반응형으로 데이터를 관리하게 돕지만 차이가 있다. ref는 원시타입(string, number)의 변화 시에도 리렌더링이 되지만, reactive는 객체나 배열에만 리렌더링이 된다.
ref, reactive 중 하나로 일관되게 작성하는 것이 혼란을 줄일 수 있다. 원시타입의 값도 관측하기 위해서는 ref를 일관되게 사용하는 것이 좋을 수 있다.
ref
import { ref } from 'vue'
const name = ref("")
// usage
console.log(name.value)
reactive
import { reactive } from 'vue'
const state = reactive({ count: 0 })
//usage
console.log(state.count)
computed, watch
computed
computed의 값은 캐싱되기 때문에 리렌더링 시 같은 값이 들어온다면 연산하지 않는다.
computed는 일반적인 매서드와는 달리 캐싱이 되기 때문에, reactive dependency에 따라 값이 계산된다.
아래 코드는 Date 객체의 반환값에 의존한다. Date.now()는 현재 시간을 반환하므로 매번 새로운 값을 반환하게 되어 있지만, computed가 의존하는 Date 객체는 reactive하지 않다. 따라서 아래 코드는 값의 변화가 발생하지 않는다.
const now = computed(() => Date.now())
한편, 아래 코드는 reactive한 name
에 의존하므로 name
이 변경되면 length
는 다시 연산된다.
import { ref, computed } from 'vue'
const name = ref("")
const length = computed(() => name.length)
watch
computed
와는 달리 사이드 이팩트를 발생시킬 목적에서 사용된다.
watch
는 캐싱한 값이 바뀌면 어떤 콜백을 실행하게 한다. watch는 값이 같더라도 연산을 다시 한다. 값의 변화를 관측하고 어떤 동작을 실행하고 싶을 때 사용한다.
watch
는 주어진 reactive state가 변경될 때 사이드이팩트를 발생시킨다.
const name = ref("")
watch(name, async () => {
const res = await fetch(`/api/users/${name}`)
const data = await res.json()
console.log(data)
})
watch를 사용할 때는 getter를 이용할 수도 있다.
const state = reactive({ count: 0 })
watch(() => state.count, (count) => {
console.log(count)
})
watchEffect
watchEffect는 별도로 소스를 지정하지 않아도 콜백함수의 reactive dependency를 조회해서 자동으로 콜백을 실행해준다.
예를들어, 아래 코드는 name에 의존하며, 즉시 실행된다. (즉시 실행 후 name 값 변화시 재실행)
watch(name, async() => {
const res = await fetch(`api/users/${name}`)
const data = await res.json()
console.log(data)
}, { immediate: true })
이 코드는 name
에만 의존하는데, 이 경우 아래처럼 더 간단히 작성할 수 있다.
watchEffect(async() => {
const res = await fetch(`api/users/${name}`)
const data = await res.json()
console.log(data)
})
참고로 watchEffect
는 동기적으로 실행될 때만 dependency를 관찰한다. 만약 위 사례처럼 비동기 콜백을 사용하게 될 경우, 처음으로 등장하는 await
키워드 직전까지 도달 가능한 프로퍼티들만 관찰 가능해진다.
요약하자면 watch
는 명시적으로 주어진 소스에 대한 변화를 관찰한다. watchEffect
는 dependency 관찰과 side effect 관리를 한번에 할 수 있다.
props로 받은 값을 state에서 사용하기
prpos로 받은 값을 단순히 read만 하지 않고 write나 update하고 싶은 경우가 있을 수 있다.
<script setup>
const props = defineProps<IProps>();
const open = ref(props.open)
const toggle = () => {
open.value = !open.value
}
</script>
<template>
<some-modal-component v-model="open" @click="toggle"/>
</template>
props 자체는 업데이트할 수 없다. 따라서 props를 child component에서 별도의 ref로 관리하고, 그 ref를 업데이트 하거나, 부모 컴포넌트에서 updater 함수를 내려주어 updater함수를 통해 부모 컴포넌트의 ref 값을 수정하게 해야 한다.
<script setup>
const props = defineProps<IProps>();
const open = computed(() => props.open)
</script>
<template>
<some-modal-component v-model="open" @click="props.toggle"/>
</template>