1.Vue3 Ref系列

149 阅读1分钟

1.ref

接收一个值返回一个响应式且可变的ref对象。ref对象仅有一个.value property,指向该内部值。

<template>
  msg: {{ msg }}
  <button @click="change">change msg</button>
</template>

<script setup lang="ts">
// ref为函数 Ref为类型
import {ref, Ref} from "vue";

const msg: Ref<string> = ref('hello')
const change = () => {
  msg.value = 'bye'
}
</script>

注:在代码中访问ref创建的响应式对象需要用.value访问,在模版中使用响应式对象不需要使用.value

2.isRef

判断一个值是不是ref响应式对象

<template>
  <button @click="estimate">
    isRef
  </button>
</template><script setup lang="ts">
import {isRef, Ref, ref} from "vue";
​
const msg: Ref<string> = ref('hello')
const num: number = 666;
const estimate = () => {
  console.log(isRef(msg)) // true 内部使用响应式对象的__v_isRef值判断
  console.log(isRef(num)) // false
}
​
</script>

3.shallowRef

浅层的ref响应式,只对第一层的.value做响应式的处理

<template>
  {{ msg.info }}
  <button @click="change">
    isRef
  </button>
</template>

<script setup lang="ts">
import {Ref, shallowRef} from "vue";

interface Msg {
  info?: string
}

// 浅层的响应式对象 只对第一层也就是.value层做响应式的监听。
// 可以作为优化性能的手段使用
const msg: Ref<Msg> = shallowRef({
  info: "hello"
})
const change = () => {
  msg.value.info = 'bye' // 此时ref对象的值会发生改变 但是视图并不会更新
  msg.value = {
    info: 'bye'
  } // 此时ref对象的值会发生改变 并且视图会更新
}
</script>

4.triggerRef

<template>
  {{ msg.info }}
  <button @click="change">
    isRef
  </button>
</template><script setup lang="ts">
import {Ref, shallowRef, triggerRef} from "vue";
​
interface Msg {
  info?: string
}
​
// 浅层的响应式对象 只对第一层也就是.value层做响应式的监听。
// 可以作为优化性能的手段使用
const msg: Ref<Msg> = shallowRef({
  info: "hello"
})
const change = () => {
  msg.value.info = 'bye' // 此时ref对象的值会发生改变 但是视图并不会更新
  // 通过 triggerRef 可以使视图强制更新
  triggerRef(msg)
}
</script>

5.customRef

自定义Ref对象

<template>
  <div>{{ msg }}</div>
  <button @click="change">change msg</button>
  <div>{{ text }}</div>
  <button @click="changeText">change text</button>
</template>

<script setup lang="ts">
import {customRef} from "vue";

function myRef<T>(value: T) {
  return customRef((track, trigger) => {
    // 必须返回一个对象
    return {
      get() {
        track() // 追踪数据
        return value
      },
      set(newValue) {
        console.log(newValue)
        value = newValue
        trigger() // 触发响应 更新视图
      }
    }
  })
}

const msg = myRef<string>('hello')
const change = () => {
  msg.value = 'bye'
}

// 应用实现一个防抖ref
function useDebouncedRef<T>(value: T, delay: number) {
  let timer: any = null
  return customRef<T>((track, trigger) => ({
    get() {
      track()
      return value
    },
    set(newValue) {
      clearTimeout(timer)
      timer = setTimeout(() => {
        value = newValue
        // ...do something
        trigger()
      }, delay)
    }
  }))
}

const text = useDebouncedRef<string>('', 2000)
const changeText = () => {
  text.value = '延迟2s出现'
}
</script>

6.Ref和shallowRef小问题

<template>
  {{ msg }}
  {{ shallowMsg.info }}
  <button @click="change">change</button>
</template>

<script setup lang="ts">
import {ref, shallowRef} from "vue"
const msg = ref('hello')
const shallowMsg = shallowRef({
  info: 'HELLO'
})
const change = () => {
  // ref的更新会造成 shallowRef的视图更新
  msg.value = 'bye'
  shallowMsg.value.info = 'BYE'
}
</script>