Skip to content

ref 与 reactive 扩展

1. ref

1.1 isRef

判断是不是一个 ref 对象, 日常使用不是很多, 多在框架源码中供开发者使用

vue
<script setup lang="ts">
import { ref, reactive, isRef } from 'vue'
// let msg = '我是App.vue'
let msg = ref('我是App.vue')
let notRef = '我不是ref'
const changeMsg = () => {
  // msg = '我被改变了'
  msg.value = '我被改变了'
  console.log('isRef(msg)', isRef(msg))
  console.log('isRef(notRef)', isRef(notRef))
}
</script>

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

1.2 shallowRef

ref() 不同,浅层 ref 的内部值将会原样存储和暴露,并且不会被深层递归地转为响应式。只有对 .value 的访问是响应式的。

提示

👉shallowRef() 常常用于对大型数据结构的性能优化或是与外部的状态管理系统集成。

vue
// App.vue
<script setup lang="ts">
import { shallowRef } from 'vue'
import HelloWorld from './components/HelloWorld.vue'

let shallow = shallowRef({ count: 1 })

console.log('shallow', shallow.value)

const changeMsg = () => {
  shallow.value.count = 2
  console.log('shallow', shallow.value)
}
</script>

<template>
  <div>{{ shallow }}</div>
  <button @click="changeMsg">change</button>
  <HelloWorld />
</template>

// HelloWorld.vue
<script setup lang="ts">
import { shallowRef } from 'vue'
let shallow2 = shallowRef({ num: 1 })
const changeMsg2 = () => {
  shallow2.value = { num: 2 }
}
</script>

<template>
  <div>{{ shallow2 }}</div>
  <button @click="changeMsg2">change</button>
</template>

1.3 triggerRef

强制触发依赖于一个浅层 ref 的副作用,这通常在对浅引用的内部值进行深度变更后使用。

1.4 customRef

创建一个自定义的 ref,显式声明对其依赖追踪和更新触发的控制方式。

customRef() 预期接收一个工厂函数作为参数,这个工厂函数接受 tracktrigger 两个函数作为参数,并返回一个带有 getset 方法的对象。

一般来说,track() 应该在 get() 方法中调用,而 trigger() 应该在 set() 中调用。然而事实上,你对何时调用、是否应该调用他们有完全的控制权。

创建一个防抖 ref,即只在最近一次 set 调用后的一段固定间隔后再调用:

vue
import { customRef } from 'vue' export 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) } } }) }

在组件中使用:

vue
<script setup>
import { useDebouncedRef } from './debouncedRef'
const text = useDebouncedRef('hello')
</script>

<template>
  <input v-model="text" />
</template>

6.6 响应式语法糖

警告

实验性 功能

响应性语法糖目前是一个实验性功能,默认是禁用的,需要显式选择使用

https://cn.vuejs.org/guide/extras/reactivity-transform.html#explicit-opt-in

语法糖 demo:

vue
<script setup>
let count = $ref(0)

console.log(count)

function increment() {
  count++ // 无需.value
}
</script>

<template>
  <button @click="increment">{{ count }}</button>
</template>

消除因引入$ref() 导致的飘红报错:

  • 第一种解决方案: 从vue/macros 引入$ref

  • 第二种解决方案: 在.d.ts 文件中写入以下内容

2. reactive

2.1 shallowReactive

一个浅层响应式对象里只有根级别的属性是响应式的。