Vue3响应式进阶API

2,436 阅读3分钟

我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第2篇文章,点击查看活动详情

shallowRef

shallow有浅层的意思,shallowRef是一种浅层形式的ref,浅层式的API创建的状态只在其顶层是响应式的,也就是说它只对.value的访问是响应式的,不会对内部值进行深层递归的响应式转换。

const user = shallowRef({
  name: '张三',
  age: 18
})

user.value.name = '李四' // 不会触发更新

// 会触发更新
user.value = {
  name: '李四', 
  age: 19
}

const list = shallowRef([{name: '张三'}])

const addUser = () => {
  list.value.push({name: '李四'}) // 不会触发更新
  
  // 会触发更新
  list.value = [
    {name: '张三'},
    {name: '李四'}
  ]
}

shallowRef可用于对大型数据结构的性能优化,例如一些比较大的列表数据,我们平时开发中通常都只需要更换最顶层的列表数据而不需要改变列表内部的值,这时可以使用shallowRef,减少一些不必要的响应式消耗。

triggerRef

triggerRef用于强制触发依赖于一个浅层ref的副作用。

如前面的代码示例中,当我们使用shallowRef后,向列表添加一个对象后并不会触发更新,这时就可以用triggerRef进行手动更新。

const list = shallowRef([{name: '张三'}])

const addUser = () => {
  list.value.push({name: '李四'}) // 不会触发更新
  
  triggerRef(list) // 手动触发list更新
}

shallowReactive

shallowReactiveshallowRef类似,它是reactive的浅层形式。与shallowRef稍有不同,shallowReactive创建的对象里只有根层级的属性是响应式的,更深层的属性会失去响应式。

const user = shallowReactive({
  name: '张三',
  son: {
    name: '小张'
  }
})

user.name = '李四' // 更改状态自身的属性会触发更新

user.son.name = '李四' // 下层嵌套对象不会触发更新

shallowReadonly

readonly不同,shallowReadonly只有根层级的属性变成只读,其他深层级的属性可以被更改。

const user = shallowReadonly({
  age: 28,
  son: {
    age: 2
  }
})

// 更改状态自身的属性会失败
user.age = 30

// 可以更改下层嵌套对象
user.son.age = 3

customRef

customRef可以创建一个自定义的ref,你可以在内部自己控制依赖追踪和更新触发的时机。

customRef是一个函数,接收两个函数参数:tracktrigger,返回一个对象,该对象包含getset两个方法。

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

<script setup>
import { customRef } from 'vue'

const useDebouncedRef = (value, delay = 500) => {
  let timeout
  return customRef((track, trigger) => {
    return {
      get() {
        track()
        return value
      },
      set(newValue) {
        clearTimeout(timeout)
        timeout = setTimeout(() => {
          value = newValue
          trigger()
        }, delay)
      }
    }
  })
}

const text = useDebouncedRef('hello')
</script>

上面代码中利用customRef实现了一个防抖ref,在get方法中进行正常的触发依赖追踪并返回值,而在set方法里做了一个防抖操作,在一段固定间隔后再进行赋值和更新。

toRaw

toRaw()可以返回由reactive()shallowReactive()readonly()等创建的代理对象的原始对象

通过toRaw()拿到的原始数据,对其进行读取或更改不会引起跟踪开销或触发更新。

const user = {
  name: '张三',
  age: 18
}

const state = reactive(user)
const raw = toRaw(state)
console.log(raw === user) // true

markRaw

markRaw可将一个对象标记为不可被转为代理。

const state = markRaw({
  name: '张三',
  age: 18
})
const user = reactive(state)

setTimeout(() => {
  user.name = '李四' // 不会触发更新
}, 3000)