본문 바로가기
Study/Vue

Vue 3 ) Ref, Refs ??

by JongIk 2022. 1. 9.
반응형

Refs

  • Vue 2 까지 쓰이던 this.$refs 를 Vue 3 의 Composition API 에서는 각각 함수로 제공됩니다.
  • setup() 함수 내에서 각 Refs 를 import 하여 사용할 수 있습니다.
ref 전달받은 기본 자료형 변수를 반응형 객체로 변경합니다. 이 객체의 value 속성을 통해서 자유롭게 변경할 수 있습니다. 일반적으로 이렇게 나온 반응형 객체를 ref 라 칭합니다.
unref ref 를 다시 일반 변수로 바꿉니다. 내부적으로 프록시 객체에서 분리하는 과정을 진행합니다.
toRef reactive API 로 생성돈 객체의 속성을 ref 를 이용해 반응형 객체로 생성합니다.
toRefs toRef 를 해당 객체의 모든 속성에 적용합니다.
isRef ref 객체인지 확인합니다.
customRef track 함수와 trigger 함수를 인자로 받고 get 과 set 함수를 리턴하는 사용자 지정 ref 를 생성합니다. get 함수에서 사용자가 필요한 일을 완료한 후 track 함수를 불러주면 되고, set 함수에서 사용자가 정의한 일을 마무리 한 후 trigger 함수를 호출하게 만들면 됩니다.
shallowRef 참조된 객체의 value 가 통째로 변경될 때만 반응형으로 작동합니다.
triggerRef shallowRef 로 참조된 객체에 대한 업데이트를 강제로 일으킵니다.

상세 설명

ref

  • 내부에 값을 가지면서 반응적이고 변경 가능한 ref 객체를 반환합니다.
  • ref 객체는 단 하나의 프로퍼티를 가지는데, 내부 값을 가리키는 .value 입니다.
const count = ref(0)
console.log(count.value) // 0

count.value++
console.log(count.value) // 1
  • 객체가 ref 의 값으로 할당되면 reactive 메소드를 통해 해당 객체에 대한 깊은 반응성을 가지게 됩니다.

타입에서의 ref

interface Ref<T> {
  value: T
}
function ref<T>(value: T): Ref<T>
  • ref 의 내부 값에 복잡한 타입을 지정해야할 경우가 있습니다.
    기본 타입 추론을 오버라이드 하기 위해 ref 를 호출 할 때 제네릭 인수를 전달하여 이를 달성할 수 있습니다.
const A = ref<string | number>('A') // foo's type: Ref<string | number>

A.value = 123 // permissible
  • 만약 제네릭의 타입을 모른다면, ref 를 Ref<T> 로 타입 캐스팅 하는것을 권장합니다.
function useState<State extends string>(initial: State) {
  const state = ref(initial) as Ref<State> // state.value -> State extends string
  return state
}

unref

  • 주어진 인자가 ref 라면 내부 값을 반환하고, 아니라면 주어진 인자를 반환합니다. 이 함수는 val = isRef(val) ? val.value : val 를 수행하는 편의 함수입니다.
  function useFoo(x: number | Ref<number>) {
    const unwrapped = unref(x) // unwrapped is guaranteed to be number now
  }

toRef

  • 소스가 되는 reactive 객체의 속성을 가져와 ref 를 만들 수 있습니다.
    이 ref 는 여기저기 인자로 전달할 수 있으면서, 소스 객체에 대해 reactive 한 연결을 유지할 수 있습니다.
  const state = reactive({
    A: 1,
    B: 2
  })

  const C = toRef(state, 'A')

  C.value++
  console.log(state.A) // 2

  state.A++
  console.log(C.value) // 3
  • toRef 는 props 의 ref 를 컴포지션 함수에 전달할 때 유용합니다.
  export default {
  setup(props) {
    useSomeFeature(toRef(props, 'foo'))
  }
}
  • toRef 는 소스객체에 해당 프로퍼티가 지금 당장 존재하지 않더라도 사용 가능한 참조를 반환합니다. 이는 toRefs 를 통해 추출되지 않는 옵션 props 를 사용하고자 할 때 유용합니다.

toRefs

  • reactive 객체를 일반 객체로 변환하여 반환하지만, 변환되는 객체의 각 프로퍼티들이 ref 로 원래의 reactive 객체 프로퍼티로 연결됩니다.
  const state = reactive({
    A: 1,
    B: 2
  })
  const stateAsRefs = toRefs(state)
  /*
  Type of stateAsRefs:

  {
    A: Ref<number>,
    B: Ref<number>
  }
  */

  // The ref and the original property is "linked"
  state.A++
  console.log(stateAsRefs.A.value) // 2

  stateAsRefs.A.value++
  console.log(state.A) // 3
  • toRefs 는 사용하는 곳에서 반응성을 읽지 않고 반환된 값을 destructure / spread 할 수 있기 때문에, 컴포지션 함수 등에서 유용하게 사용됩니다.
  function useFeatureX() {
    const state = reactive({
      foo: 1,
      bar: 2
    })

    // logic operating on state

    // convert to refs when returning
    return toRefs(state)
  }

  export default {
    setup() {
      // can destructure without losing reactivity
      const { foo, bar } = useFeatureX()

      return {
        foo,
        bar
      }
    }
  }
  • toRefs 는 소스 객체에 포함된 속성에 대한 ref 만 생성합니다.
    특정 속성에 대한 참조를 만들려면 toRef 를 사용하세요

isRef

  • 주어진 값이 ref 객체인지 확인합니다.

customRef

  • 종속성 추적 및 업데이트 트리거를 명시적으로 커스터마이징 할 수 있는 ref 를 만듭니다.
    track 및 trigger 함수를 인수로 받고 get 및 set 을 가진 객체를 반환하는 팩토리 함수를 인자로 넘겨야 합니다.
  • cumstomRef 를 이용해 v-model 에 대해 debounce 를 구현
  <input v-model="text" />
function useDebouncedRef(value, delay = 200) {
  let timeout
  return customRef((track, trigger) => {
    return {
      get() {
        track()
        return value
      },
      set(newValue) {
        clearTimeout(timeout)
        timeout = setTimeout(() => {
          value = newValue
          trigger()
        }, delay)
      }
    }
  })
}

export default {
  setup() {
    return {
      text: useDebouncedRef('hello')
    }
  }
}

shallowRef

  • 자신의 .value 가 변경되는 것은 추적하지만, value 값 자체를 반응적으로 만들지 않는 ref 를 만듭니다.
const foo = shallowRef({})
// ref의 .value가 변경되는것은 반응하지만 
A.value = {}
// 값 자체는 반응형이 아님
isReactive(A.value) // false 

triggerRef

  • shallowRef 에 연결된 모든 effect 를 수동으로 실행합니다.
const shallow = shallowRef({
  greet: 'Hello, world'
})

// Logs "Hello, world" once for the first run-through
watchEffect(() => {
  console.log(shallow.value.greet)
})

// This won't trigger the effect because the ref is shallow
shallow.value.greet = 'Hello, universe'

// Logs "Hello, universe"
triggerRef(shallow)

참고문서 : Vue3 공식문서

반응형

댓글