toRef, toRefs

Front-end Vue

toRef?

toRef()는 반응형 객체의 속성을 하나의 ref 객체로 만들 때 사용한다.

생성된 ref 객체는 원본 반응형 객체의 속성과 동기화된다. 원본 속성을 변경하면 ref 객체가 업데이트되며, 그 반대의 경우도 마찬가지이다.

const state = reactive({ foo: 1, bar: 2 }) 
const fooRef = toRef(state, 'foo') 

// 참조를 변경하면 원본이 업데이트됩니다. 
fooRef.value++ 
console.log(state.foo) // 2 

// 원본을 변경하면 ref도 업데이트됩니다. 
state.foo++ 
console.log(fooRef.value) // 3

ref, toRef의 차이

const fooRef = ref(state.foo)

위 예제의 ref 객체(fooRef)는 primitive 값을 초기화 값으로 받기 때문에 state.foo와 동기화되지 않는다.

toRef 활용

toRef()는 Composable 함수에 Props 참조를 전달하는 경우에 유용하다.

import {toRef} from 'vue'

const props = defineProps(/* ... */)

// props.foo를 ref형태로 변환한 다음 composable에 적용
useMyFeature(toRef(props, 'foo'))

toRef()props와 함께 사용되면 props 변경에 대한 제한사항이 적용된다. ref에 새 값을 할당하려는 시도는 prop을 직접 수정하려는 것과 동일하게 판단되며 허용되지 않는다.

새 값을 할당하려는 상황이라면 toRef() 대신 computed(get, set)`를 활용하는 것이 좋다.

그리고 toRef는 반응형 객체의 속성이 존재하지 않아도 사용 가능한 ref 객체를 반환한다.

toRefs?

반응형(reactive) 객체를 구조분해할당 후 반응형을 그대로 유지하려고 할 때 한다.

반응형 객체를 구조분해하여 재할당 할 경우 반응형으로 동작하지 않는다. (call by value가 되기 때문)

let position = reactive({ x: 0, y: 0, })
let { x, y } = position
x++ 
y++
console.log(x, y) // 1 1 
console.log(position.x, position.y) // 0 0

이 때 반응성을 유지하기 위해 reactive 객체의 각각의 속성을 ref로 변환해 주는 것이 toRefs()이다.

toRefs를 사용하면 reactive 객체 각각의 속성이 ref 값으로 변환된다. 그렇기 때문에 구조분해할당으로 재할당을 받게 되면 재할당 받은 ref 참조 값(예제에서는 x, y)과 reactive 객체의 속성이 동기화된다.

let position = reactive({ x: 0, y: 0, })
let { x, y } = toRefs(position)
x.value++
y.value++
console.log(x.value, y.value) // 1 1 
console.log(position.x, position.y) // 1 1

toRefs 활용

toRefs()는 일반 함수나 Composable 함수에서 Reactive 객체를 반환받는 경우에 유용하게 사용된다.

const useMyFeature = () => {
  const state = reactive({ foo: 1, bar : 2 })

  /* composable fn logic operating on state ... */
  
  return toRefs(state) // refs 형태로 반환
}

const { foo, bar } = useMyFeature() // reactivity 를 가진 채 구조분해할당 가능

Composable 함수 내에서 반환값을 ref로 반환해야 하는 컨벤션이 있다.

하지만 Composable 함수 내에서 reactive 객체를 사용하고 싶을 때가 있을 때는 toRefs() 함수를 사용하여 내부에서 사용한 reactive 객체를 ref로 변환하여 반환할 수 있다.