Vue 改进了响应式 API 中 getter 的用法!

2023-04-0317:09:11WEB前端开发Comments942 views字数 2235阅读模式
Vue 改进了响应式 API 中 getter 的用法!
出品 | 前端充电宝(ID:FE-Charge)

Vue 改进了响应式 API 中 getter 的用法,主要包括:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/32702.html

  • 一个用于将不同来源(value / ref / getter)规范化为的 API(通过引入 toValue()
  • 一个用于将不同来源(value / ref / getter)规范化为引用的 API(通过增强 toRef()
  • 引入 MaybeRef<T> 和 MaybeRefOrGetter<T> 类型

通常需要将状态传递到组合式函数中并保持响应性。在大多数情况下,这意味着要将响应源转换为 ref:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/32702.html

import { toRef } from 'vue'

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

useFeature(toRef(props, 'foo'))

目前,toRef 仅用于从对象中“提取”单个属性。这就有点不灵活,例如,如果想将嵌套属性转换为 ref:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/32702.html

useFeature(toRef(props.foo, 'bar'))

上面的代码有两个问题:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/32702.html

  • 调用 toRef 时 props.foo 可能不存在
  • 如果 props.foo 被交换到不同的对象,这将无法处理这种情况。

为了解决这个问题,可以使用 computed文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/32702.html

useFeature(computed(() => props.foo?.bar))

但是,在这里使用 computed 并不是最佳选择。在内部,computed 创建一个单独的 effect 来缓存计算值。当 getter 只访问属性而不执行任何昂贵的计算时,这实际上是很大的开销。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/32702.html

将非引用响应状态传递到组合式函数的成本最低的方法就是用 getter 包装它(或“thunking”——即延迟实际值的访问,直到调用 getter):文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/32702.html

useFeature(() => props.foo?.bar)

VueUse 已经广泛支持这种模式,这也有点类似于在 Solid 中看到的函数式 signals(信号)。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/32702.html

此外,这种模式在使用响应式 props 解构时会很常用:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/32702.html

const { foo } = defineProps<{ foo: string }>()

useFeature(() => foo)

引入 toValue()

在组合式函数中,其参数可以接受值或引用。这可以表示为:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/32702.html

type MaybeRef<T> = T | Ref<T>

为了也支持 getters,接受的类型将是:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/32702.html

type MaybeRefOrGetter<T> = MaybeRef<T> | (() => T)

目前提供的unref将 MaybeRef<T> 规范化为 T。但是,不能让 unref 也解包 getter,因为这将是一个破坏性的变化。可以在函数值上调用 unref 并期望返回该函数。这种情况比较少见,但仍然是无法破解的可能情况。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/32702.html

因此,引入一个新方法,toValue()文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/32702.html

export function toValue<T>(source: MaybeRefOrGetter<T>): T {
  return isFunction(source) ? source() : unref(source)
}

这就相当于 VueUse 的 [resolveUnref()](https://vueuse.org/shared/resolveUnref/)。这里将其命名为 toValue() 是因为它与 toRef() 相反:两者代表两个不同的规范化方向:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/32702.html

ref <- toRef() - ref/value/getter - toValue() -> value

增强 toRef()

当然也可能存在需要 ref 的情况——不能传递 getter。对于这种情况,仍然可以使用 computed。但如前所述,computed 对于只访问属性的简单 getter 来说是一种矫枉过正。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/32702.html

可以向 toRef() 添加新的重载,以便它现在可以接受 getters :文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/32702.html

const ref = toRef(() => 123)
ref.value // 123

以这种方式创建的 ref 是只读的,只是在每次访问 .value 时调用 getter文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/32702.html

toRef() 现在应该被视为“将 value / ref / getter 规范化为 refs” 的 API:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/32702.html

// value -> Ref
toRef(1) // Ref<number>

// Ref -> Ref
toRef(ref(1)) // Ref<number>

// getter -> Ref
toRef(() => 1) // Ref<number>

这就相当于 VueUse 的 [resolveRef()](https://vueuse.org/shared/resolveRef/)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/32702.html

现在仍然支持旧的 toRef(object, 'key') 用法,但应该首选更灵活的 getter 语法:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/32702.html

toRef(() => object.key)

向后移植到 v2.7?

将这些功能添加在 v3.3 和 v2.7 之间造成了差异——虽然理论上不再回向 v2.7 添加新的功能,但这些可能值得向后移植以确保 vue-demi 和依赖于 vue-demi 的 VueUse 的行为一致性。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/32702.html

如果向后移植到 2.7,VueUse 也可以用 toRef 和 toValue 来替换 resolveRef 和 resolveUnref文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/32702.html

参考:https://github.com/vuejs/core/pull/7997文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/32702.html

文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/32702.html
  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/gcs/32702.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定